You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

解决方案

问题根源

  1. 直接修改state数组:你通过driverData.push()和FullData.push()直接修改了state中的数组,再用setFullData(FullData)更新状态。由于数组是引用类型,React检测不到数组的变化,因此不会触发组件重新渲染。
  2. 异步请求未批量处理:遍历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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 09:10:54