无法将Firestore数据加载至React Native FlatList,求解决方案
问题原因与修复方案
你的代码存在几个关键问题,导致数据无法渲染到FlatList中,页面一直显示加载动画:
1. 错误更新exerciseList状态
在getExercise函数中,你通过forEach循环逐个更新exerciseList,但每次都将数组替换为单个对象(setExerciseList({...})),最终exerciseList变成了对象而非数组,exerciseList.length会变为undefined,因此判断条件exerciseList.length > 0始终不成立,一直显示加载动画。
修复方式:先收集所有文档数据到一个数组,再一次性更新状态:
const getExercise = async() => { const querySnapshot = await getDocs(collection(db, "Exercise")); const exercises = []; querySnapshot.forEach((doc) => { console.log(doc.id, doc.data()); exercises.push({ ...doc.data(), id: doc.id, }); }); setExerciseList(exercises); };
2. 字段名不匹配
- 你在添加数据时,Firestore中存储的字段是
title,但在获取数据时错误地使用了doc.exerciseTitle,这会导致title字段为空; - FlatList的
renderItem中也错误地使用了item.exerciseTitle,应该对应item.title。
3. 组件名错误
你导入的组件是Exercise,但在renderItem中使用了不存在的ExerciseItem,需要改为Exercise。
4. 练习数量显示固定值
noOfExercises的文本固定为0,应该改为显示exerciseList.length来实时反映数据数量。
完整修正后的代码
import { Pressable, Text, TextInput, View, StyleSheet, SafeAreaView, FlatList, ActivityIndicator } from 'react-native' import React, { useState, useEffect } from 'react' import Exercise from '../../components/Exercise' import { MaterialIcons } from '@expo/vector-icons'; import { auth, app, db, getFirestore, collection, addDoc, getDocs } from '../../firebase' const WorkoutScreen = () => { const [exerciseTitle, setTitle] = useState(''); const [exerciseList, setExerciseList] = useState([]); const addExercise = async() => { try { const docRef = await addDoc(collection(db, "Exercise"), { title: exerciseTitle, isChecked: false, }); console.log("Document written with ID: ", docRef.id); setTitle(""); // 添加后重新获取数据,更新列表 getExercise(); } catch (e) { console.error("Error adding document: ", e); } }; const getExercise = async() => { const querySnapshot = await getDocs(collection(db, "Exercise")); const exercises = []; querySnapshot.forEach((doc) => { console.log(doc.id, doc.data()); exercises.push({ ...doc.data(), id: doc.id, }); }); setExerciseList(exercises); }; useEffect ( () => { getExercise(); }, []); return ( <SafeAreaView style={styles.container}> <View style={styles.header}> {/* heading */} <Text style={styles.heading}>Workout List</Text> {/* shopping items */} <Text style={styles.noOfExercises}>{exerciseList.length}</Text> {/* delete all */} <Pressable> <MaterialIcons name="delete" size={32} color="black" /> </Pressable> </View> {exerciseList.length > 0 ? ( <FlatList data={exerciseList} renderItem ={({item}) => <Exercise title={item.title}/>} keyExtractor={(item) => item.id} /> ) : ( <ActivityIndicator /> )} <TextInput placeholder='Enter Excercise' style={styles.input} value={exerciseTitle} onChangeText={(text) => setTitle(text)} onSubmitEditing={addExercise} /> </SafeAreaView> ) } export default WorkoutScreen const styles = StyleSheet.create({ container: { flex: 1, }, header: { flexDirection: 'row', width: '90%', alignSelf: 'center', padding: 10, justifyContent: 'space-between', alignItems: 'center', marginBottom: 10, }, heading: { fontWeight: '900', fontStyle: 'bold', fontSize: 30, flex: 1, marginTop: 20, }, noOfExercises: { fontSize: 20, fontWeight: '500', marginRight: 20, }, input: { backgroundColor: 'lightgrey', padding: 10, fontSize: 17, width: '90%', alignSelf: 'center', marginTop: 'auto', borderRadius: 10, } })
额外优化:在addExercise函数中添加数据后调用getExercise(),确保新增数据能实时刷新显示。
内容的提问来源于stack exchange,提问作者Dan123
相关产品推荐
相关产品推荐

