0

I'm trying to fetch data from firebase. I want to push the values in an array and map through it in a view. The only problem is that i can see the values in my array but not outside the .then function.

const dataArray = []
  
  firebase
    .database()
    .ref("Challenges/Day")
    .once("value")
    .then((snapshot) => {
      snapshot.forEach((child) => {
        dataArray.push(child.val());
      });
      console.log(dataArray)
    });


  return (
    <View style={styles.text}>
      {dataArray.map((data) => {
        <Text>{data}</Text>;
      })}
    </View>
  );

if i console log it then the output is : Array [ "eat", "sleep", ] But outside it's function my array is empty.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807

2 Answers2

3

The issue here is console.log() is getting executed even before the data is returned from the firebase as response. When the request is made it takes sometime (say 1 sec) to return the response, but in the meantime the control executes the next line which is console.log(). When this line is executed, the value of dataArray=[] at that amoment. So for your case it is best to keep dataArray as state variable, so when the response is returned you can set the value of the dataArray which will re-render your component, thus displaying its return value.

const [dataArray,setDataArray] = useState([])
  
  firebase
    .database()
    .ref("Challenges/Day")
    .once("value")
    .then((snapshot) => {
      let tempArray=[];
      snapshot.forEach((child) => {
        tempArray.push(child.val());
      }
      setDataArray(tempArray);
      );
      console.log(dataArray)
    });


  return (
    <View style={styles.text}>
      {dataArray.map((data) => {
        <Text>{data}</Text>;
      })}
    </View>
  );
Hardik3296
  • 336
  • 2
  • 14
2

It's due to 2 issues you are facing.

  1. asynchrounous - means what you are seeing in UI is the [] before firebase is executed.
  2. state update - there were no state updated, hence even after the variable change occurred in firebase, the UI is not updated. Any normal variable changes will not re-render the UI, only a *state change will trigger a re-render in React.

What you can do.

const [dataArray, setDataArray] = useState([])

useEffect(() => {
   firebase
   .database()
   .ref("Challenges/Day")
   .once("value")
   .then((snapshot) => {
     snapshot.forEach((child) => {
    //call an update to the array.
    //setDataArray((oldDataArray) => oldDataArray.push(child.val()))
      setDataArray((oldDataArray) => [...oldDataArray, child.val()])
    });
      console.log(dataArray)
    });
}, []); //will only initialize once(on mount). Putting outside will get called again and again when state change.

return (
<View style={styles.text}>
  {dataArray.map((data) => {
    <Text>{data}</Text>;
  })}
</View>
);
Han
  • 728
  • 5
  • 17
  • then i get an error: TypeError: oldDataArray.push is not a function. (In 'oldDataArray.push(child.val())', 'oldDataArray.push' is undefined)] – J van Schaik Dec 29 '20 at 15:10
  • my mistake, suppose to be: setDataArray((oldDataArray) => [...oldDataArray, child.val()]); https://stackoverflow.com/questions/59100863/how-to-set-state-array-using-react-hooks – Han Dec 29 '20 at 17:03
  • the only problem now is that i get the same value a hundred times. But i'm getting close. Thank you! – J van Schaik Dec 30 '20 at 09:50
  • make sense, seems your database got initialized again and again. I suggest this change..see the modified. – Han Dec 31 '20 at 14:23