React Native+Firestore列表加载异常:仅手动刷新才显示
问题:Firestore数据获取完成后FlatList无法自动显示内容
我正在开发基于Firestore数据库的Expo React Native应用,编写了如下代码。目前数据可正常获取,但列表仅在手动刷新(Ctrl+S)时才显示,请问如何实现屏幕加载时自动显示列表?
function ViewServices () { const navigation = useNavigation(); const [FullData, setFullData] = useState([]); const [driverData, setDriverData] = useState([]); // Retrieving Data useEffect(() => { firebase.firestore().collection('driver') .get() .then(snapshot => { if (snapshot.empty) { console.log('Empty'); return; } snapshot.forEach(doc => { driverData.push( { id: doc.id, }); }); { driverData? driverData.map((point) => ( firebase.firestore().collection('driver') .doc(point.id) .collection('personal') .get() .then(snapshot => { if (snapshot.empty) { alert('Nothing To Show'); return; } snapshot.forEach(doc => { FullData.push( { id : doc.id, name: (doc.data().firstname), school: (doc.data().lastname), }); }); setFullData(FullData); }) .catch(err => { console.log('Error getting documents', err); }) )) : null} }) .catch(err => { console.log('Error getting documents', err); }); }, []); return( <FlatList data={FullData} renderItem={({ item }) => ( <View style={{ height: 50, flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>User ID: {item.id}</Text> <Text>User Name: {item.name}</Text> </View> )} /> )}
解决方案
问题根源
- 直接修改state数组:你通过
driverData.push()和FullData.push()直接修改了state中的数组,再用setFullData(FullData)更新状态。由于数组是引用类型,React检测不到数组的变化,因此不会触发组件重新渲染。 - 异步请求未批量处理:遍历driverData发起的Firestore请求是异步的,你在每个请求完成后单独更新state,不仅会导致多次不必要的渲染,还可能因为所有请求未完成就提前更新,导致数据不完整。
修复后的代码
function ViewServices() { const navigation = useNavigation(); const [fullData, setFullData] = useState([]); // 改用小驼峰命名更符合JS规范 useEffect(() => { const fetchData = async () => { try { // 第一步:获取所有driver文档 const driverSnapshot = await firebase.firestore().collection('driver').get(); if (driverSnapshot.empty) { console.log('No drivers found'); return; } // 第二步:批量获取每个driver下的personal数据 const personalPromises = driverSnapshot.docs.map(async (driverDoc) => { const personalSnapshot = await firebase.firestore() .collection('driver') .doc(driverDoc.id) .collection('personal') .get(); if (personalSnapshot.empty) { return null; // 无数据则返回null } // 转换personal文档为数据对象 return personalSnapshot.docs.map(doc => ({ id: doc.id, name: doc.data().firstname, school: doc.data().lastname, })); }); // 等待所有异步请求完成,合并结果 const results = await Promise.all(personalPromises); // 过滤掉null值,合并成一维数组 const combinedData = results.flat().filter(item => item !== null); // 更新state,使用新数组触发重新渲染 setFullData(combinedData); } catch (err) { console.log('Error fetching data', err); } }; fetchData(); }, []); return ( <FlatList data={fullData} renderItem={({ item }) => ( <View style={{ height: 50, flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>User ID: {item.id}</Text> <Text>User Name: {item.name}</Text> </View> )} keyExtractor={(item) => item.id} // 添加keyExtractor优化FlatList性能 /> ); }
关键修改点
- 使用
async/await替代嵌套的.then(),让代码更易读且便于批量处理异步请求 - 用
Promise.all()等待所有personal数据请求完成后再统一更新state,避免多次渲染 - 始终创建新数组(而不是修改原state数组)来更新状态,确保React能检测到变化并触发重新渲染
- 添加
keyExtractor属性,符合FlatList的最佳实践,提升性能 - 变量名改用小驼峰命名,符合JavaScript代码规范
内容的提问来源于stack exchange,提问作者ab_404
相关产品推荐
相关产品推荐

