Как получить данные с помощью двух запросов к хранилищу данных в React Native
В моей базе данных firestore я сослался на коллекцию Zutaten внутри коллекции Meal. Теперь я пытаюсь отобразить данные из коллекции Zutaten внутри моего компонента списка. Вconsole.log('ingredient data: ', documentSnapshot.data())
Оператор внутри моего второго снимка работает правильно и отображает данные из коллекции Zutaten. Но я не могу получить доступ к данным вне функции useEffect, поэтому я думаю, что ошибся с обработчиками реакции. Мой код:
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 ответ
Это действительно работает, как ожидалось. Поскольку все данные загружаются из Firestore асинхронно, они доступны только в обратном вызове. Итак, ваши звонкиsetMeal
а также setLoading
должно произойти внутри этого обратного вызова.
Самый простой способ сделать это - позвонить 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);
});