如何在 React Native 中使用两个 firestore 查询获取数据

How to get data using two firestore queries in react native

在我的 firestore 数据库中,我在 Meal 集合中引用了 Zutaten 集合。 现在我尝试在我的列表组件中显示来自 Zutaten 集合的数据。 我的第二个快照中的 console.log('ingredient data: ', documentSnapshot.data()) 语句正常工作并显示 Zutaten 集合中的数据。 但是我无法访问 useEffect 函数之外的数据,所以我认为我在使用 react-hooks 时犯了一个错误。 我的代码:

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>
      )}
    />
  );
}

这实际上按预期工作。由于所有数据都是从 Firestore 异步加载的,因此它仅在回调中可用。因此,您对 setMealsetLoading 的调用将需要在该回调内进行。

最简单的方法是在循环内调用 setMeal,如下所示:

  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);
    });

使用此代码,您现在可以在每次向其中添加条目时渲染餐点。


更新:如果您还渲染成分(我在您共享的代码中没有看到),您需要将其设置为加载成分的回调。

  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);
    });