0

I am having some difficulty obtaining data from multiple Firebase .on calls. The problem is that I am getting repeat listings because I am pushing the data into an array called items, but I am not sure how I can clear this array when the data should be updated (causing repeats). I have tried using componentWillUpdate() and componentDidUpdate() lifecycle methods, but the .on calls seem to update without alerting them.

I would place the items array inside one of the .on calls, but then I am not sure how I can push data into it from the other '.on' calls.

The way my database is structured is that there are objects called "cars", each "cars" object can have multiple properties, the most important (for me) being "model". There are several cars that have the same model, but I am trying to get the very last "cars" object for each model. So, if I have Accord, Civic, Sentra, etc, I want the last Accord, the last Civic, the last Sentra, and so on.

This is the code I am currently using:

import React from 'react'; 
import { View, Text, FlatList } from 'react-native'; 
import firebase from 'react-native-firebase'; 
import TypeItem from './TypeItem'; 

DB = firebase.database().ref('cars/'); 


export default class LatestType extends React.PureComponent {
    constructor(props) {
        super(props); 
        this.state = {
            data: []
        }; 
        this.pushReports = this.pushReports.bind(this); 
        this.makeRemoteRequest = this.makeRemoteRequest.bind(this); 
    }

    makeRemoteRequest = () => {
        let items = []; 
        models.forEach(element => {  //models is an array of the list of models
            this.pushReports(element, items); 
        });
        console.log("These are the items from Status Screen: ",items); 
    }

    pushReports = (model, items) => {
        let item = {}; 
        DB.orderByChild("model")
        .equalTo(model) 
        .limitToLast(1)
        .on("child_added", snap => {
            item = {
                key: snap.key, 
                type: snap.val().type, 
                model: snap.val().model, 
            }
            items.push(item); 
            this.setState({
                data:items
            });
        }); 
    }

    componentWillMount(){
        this.makeRemoteRequest(); 
    }

    componentWillUnmount(){
        DB.off(); 
    }



    render() {
        return (
            <View>
                <FlatList 
                    data={this.state.data}
                    renderItem={({item}) => <TypeItem item={item} />}
                />
            </View>
        );
    }
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
user8951490
  • 833
  • 1
  • 10
  • 21
  • Please paste snapshot of your firebase nodes – Himanshu Jan 29 '18 at 12:39
  • you using `this.setState({data:items});` inside `.on` function . you should use it outside on function. Since `on` function is called each time for every child. Checkout this link difference between [on and once](https://stackoverflow.com/questions/47572171/difference-between-firebase-onvalue-and-oncevalue). Use it according to your requirement – Himanshu Jan 29 '18 at 12:54
  • I know the difference between on and once (I need on because I need it to constantly update when a new item is added), the problem is with clearing the items array. Furthermore, when I place setState outside of the .on function, it does not update at all, then it is only an empty array when I log this.state.data. – user8951490 Jan 29 '18 at 14:46
  • Is there a way to wait until the .on method is complete? I tried using `then` but I got an error that then is not a method. – user8951490 Jan 29 '18 at 16:14

1 Answers1

1

Try

this.setState({
  data:[...items]
});

instead your

this.setState({
  data:items
});
  • Where should I place that? Inside the .on block? – user8951490 Jan 29 '18 at 16:13
  • Tried it inside and outside the .on block, still have the same problem for both scenarios. – user8951490 Jan 29 '18 at 16:20
  • Are you sure that you receive items from server ? – Oleksandr Cherniavenko Jan 29 '18 at 16:25
  • Try add `console.log('New update:',item, 'New items:', items);` before `this.setState` – Oleksandr Cherniavenko Jan 29 '18 at 16:26
  • I am getting the items from the Firebase cloud, but the problem is there are duplicates... I just want the last item for every possibility in the models array. That's why I think the real problem lies in refreshing the items array. – user8951490 Jan 29 '18 at 16:34
  • You can either clear duplicates from array ( if you have `id` ) or change data structure from array to object like and then iterate over object values using `Object.values()` const items = { [model.id]: item, [model.id]: item, }; – Oleksandr Cherniavenko Jan 29 '18 at 16:40
  • Delete duplicates -> https://stackoverflow.com/questions/15125920/how-to-get-distinct-values-from-an-array-of-objects-in-javascript – Oleksandr Cherniavenko Jan 29 '18 at 16:41
  • Thank you for your effort Oleksandr, but I need the very latest value per model, which makes deleting duplicates more complicated than a list of unique values. Do you know how to wait until the .on method is complete? I believe it is async, but when I place a ".then" function at the end of it or an await in front of it, I get an error. I think if I can wait, then I at least get a better idea of when to setState. – user8951490 Jan 30 '18 at 08:32