0
votes

In my firestore database i have referenced the Zutaten collection inside the Meal collection. Now i try to display the data from the Zutaten collection inside my list component. The console.log('ingredient data: ', documentSnapshot.data()) statement inside my second snapshot works properly an displays the data from the Zutaten collection. But i can't access the data outside the useEffect function, so i think i made a mistake with react-hooks. My code:

function Meal() {
  const [loading, setLoading] = useState(true);
  const [meal, setMeal] = useState([]); // Initial empty array of meal
  const [ingredient, setIngredient] =  useState([]);
  
  useEffect(() => {
    const subscriber = firestore()
      .collection('Meal')
      .onSnapshot((querySnapshot) => {
        const meal = [];
        querySnapshot.forEach(documentSnapshot => {
          meal.push({
            ...documentSnapshot.data(),
            //key: documentSnapshot.id,
        });
          const ingredient = [];
          for (let i=0; i<documentSnapshot.data().Zutaten.length; i++) {
            documentSnapshot.data().Zutaten[i].get().then(documentSnapshot => {
              if (documentSnapshot.exists) {
                console.log('ingredient data: ', documentSnapshot.data())
                ingredient.push({
                  ...documentSnapshot.data(),
                  //key: documentSnapshot.data().id,
                });
              };
            })
            setIngredient(ingredient);
          }
      });
      setMeal(meal);
      setLoading(false);
    });

    // Unsubscribe from events when no longer in use
    return () => subscriber();
  }, []);

  console.log('this is it: ', ingredient);
  

  if (loading) {
    return <ActivityIndicator />;
  }

  return (
    <List
      style={styles.container}
      contentContainerStyle={styles.contentContainer}
      data={meal}
      renderItem={({ item }) => (
        <Card style={styles.item}>
          <Text style={styles.title}> {item.Name}  </Text>
          <Layout>
            <Image
              style={{ height: 128, borderRadius: 5, borderWidth: 2, borderColor: 'black', marginHorizontal: -20 }}
              source={{ uri: item.srcImage}}
            />
          </Layout>
        </Card>
      )}
    />
  );
}
1

1 Answers

0
votes

This is actually working as expected. Since all data is loaded from Firestore asynchronously, it is only available in the callback. So your calls to setMeal and setLoading will need to happen inside that callback.

The simplest way to do that is to call setMeal inside the loop like this:

  useEffect(() => {
    const subscriber = firestore()
      .collection('Meal')
      .onSnapshot((querySnapshot) => {
        const meal = [];
        querySnapshot.forEach(documentSnapshot => {
          meal.push({
            ...documentSnapshot.data(),
            //key: documentSnapshot.id,
          });
          setMeal(meal); // this is moved
          const ingredient = [];
          for (let i=0; i<documentSnapshot.data().Zutaten.length; i++) {
            documentSnapshot.data().Zutaten[i].get().then(documentSnapshot => {
              if (documentSnapshot.exists) {
                console.log('ingredient data: ', documentSnapshot.data())
                ingredient.push({
                  ...documentSnapshot.data(),
                  //key: documentSnapshot.data().id,
                });
              };
            })
            setIngredient(ingredient);
          }
      });
      setLoading(false);
    });

With this code you now render the meal each time you add an entry to it.


Update: if you're also rendering the ingredients (I didn't see that in the code you shared), you will need to set that to the state inside the callback where you load the ingredients.

  useEffect(() => {
    const subscriber = firestore()
      .collection('Meal')
      .onSnapshot((querySnapshot) => {
        const meal = [];
        querySnapshot.forEach(documentSnapshot => {
          meal.push({
            ...documentSnapshot.data(),
            //key: documentSnapshot.id,
          });
          setMeal(meal); // this is moved
          const ingredient = [];
          for (let i=0; i<documentSnapshot.data().Zutaten.length; i++) {
            documentSnapshot.data().Zutaten[i].get().then(documentSnapshot => {
              if (documentSnapshot.exists) {
                console.log('ingredient data: ', documentSnapshot.data())
                ingredient.push({
                  ...documentSnapshot.data(),
                  //key: documentSnapshot.data().id,
                });
              };
              setIngredient(ingredient); // move this too
            })
          }
      });
      setLoading(false);
    });