0

I saw similar questions online but none of their solutions worked for me.

I am building an app in React Native which loads information from firebase and then displays it. I want to load objects from firebase, put them in an array and then set the state so the class would re-render and display it once it's loaded.

The information is being loaded fine, but I can't find a way to call setState after the array has loaded. I tried promises and tried using another function as a callback, but nothing had worked for me yet. It always executes setState before the array is loaded. I don't know if using setTimeout in some way would be a good solution though.

Here is the some of the code (I want to update the jArray in this.state and then re-render the page) :

constructor(props){
  super(props);
  this.state = {
    jArray: []
  }
}

componentDidMount(){         
   this.getJ(); 
}

async getJ(){

  let jArray = [];
  let ref = database.ref('users/' + fb.auth().currentUser.uid + '/usersJ');
  let snapshot = await ref.once('value');

  let itemProcessed = 0;
  let hhh = await snapshot.forEach(ch => {
     database.ref('J/' + ch.val()).once('value')
      .then(function(snapshot1){
        jArray.push(snapshot1);
        itemProcessed++;
        console.log(itemProcessed);
        if(snapshot.numChildren()===jArray.length){
          JadArray = jArray
        }
      })
  });

}

Thanks (:

YosefBro
  • 596
  • 1
  • 7
  • 17

2 Answers2

0

Maybe you can do something like this:

  // don't forget to use an arrow function to bind `this` to the component
  getJ = async () => {
    try {
      const ref = database.ref('users/' + fb.auth().currentUser.uid + '/usersJ');
      const snapshot = await ref.once('value');

      // it might be easier just to start by getting the data into an object you can use like this
      const dataObj = snapshot.val();

      // extract the keys
      const childKeys = Object.keys(dataObj);

      // use the keys to create a function that makes an array of all the promises we want
      const createPromises = () =>
        childKeys.map(childKey => database.ref('J/' + childKey).once('value'));

      // await ALL the promises before moving on
      const jArray = await Promise.all(createPromises());

      // now you can set state
      this.setState({ jArray });

      // remember to catch any errors
    } catch (err) {
      console.warn(err);
      // you might want to do something else to handle this error...
    }
  };
}
Flagship1442
  • 1,688
  • 2
  • 6
  • 13
  • Thank you very much for that. I tried your solution but there were some problems with the promises and I kinda got lost. I found a strange and nice solution that lets me to setState inside the loop and it works fine now. – YosefBro Apr 03 '20 at 06:43
0

So in the end I found a solution to my problem, from: https://stackoverflow.com/a/47130806/3235603

My code looks like this:

async getJ(){

  let jArray = [];
  let ref = database.ref('users/' + fb.auth().currentUser.uid + '/usersJ');
  let snapshot = await ref.once('value');

  let itemProcessed = 0;
  let that = this;
  let hhh = await snapshot.forEach(ch => {
     database.ref('J/' + ch.val()).once('value')
      .then(function(snapshot1){
        jArray.push(snapshot1);
        itemProcessed++;
        console.log(itemProcessed);
        if(snapshot.numChildren()===jArray.length){
          JadArray = jArray
          that.setState({
            jadArray : jArray,
            dataLoaded : true
          },() => console.log(that.state))
        }
      })
  });
}

It's kinda a tricky one with 'this' and 'that', but it all works fine now.

YosefBro
  • 596
  • 1
  • 7
  • 17