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

如何解决React Native首次重载时useState数组为空的问题?

React Native 应用重载时useState数组为空的问题解决

问题概况

应用启动重载时,users状态数组为空,界面无内容显示;仅在VS Code保存代码触发热重载后,才能正常加载并展示收藏的freelancer列表。尝试两种useEffect写法均存在问题:

  • 无依赖项的useEffect无法正确获取数据
  • 添加users作为依赖项后触发无限循环

原代码问题分析

  1. 异步逻辑处理错误:原代码中onSnapshot是异步实时监听回调,querySnapshot.forEach内的async函数不会被forEach等待,导致setUsers(userArray)执行时,userArray还未被填充数据。
  2. 实时监听误用:若仅需一次性获取数据,使用onSnapshot会导致回调延迟触发,初始渲染时无法拿到数据;若需实时监听,原代码未正确处理多次回调的状态更新逻辑。
  3. 依赖项不合理:将users加入依赖项后,每次setUsers都会更新users状态,进而触发useEffect重复执行,形成无限循环。

修复方案

方案1:一次性获取数据(无需实时更新)

使用getDoc替代onSnapshot,通过Promise.all等待所有用户数据获取完成后再更新状态,同时用useRef标记是否已获取数据,避免重复执行。

import { useEffect, useState, useRef } from 'react';
import { getDocs, query, collection, where, getDoc, doc } from 'firebase/firestore';

// ... 组件其他代码
const [users, setUsers] = useState([]);
const isFetched = useRef(false); // 标记数据是否已获取

useEffect(() => {
  const fetchFavUsers = async () => {
    if (isFetched.current) return;
    try {
      // 查询当前用户的收藏列表
      const q = query(
        collection(db, "favoritFreelancer"),
        where("cid", "==", userUid)
      );
      const querySnapshot = await getDocs(q);

      // 批量获取收藏用户的详细数据
      const userPromises = querySnapshot.docs.map(async (favUser) => {
        const userDoc = await getDoc(doc(db, "users", favUser.data().lancerID));
        return userDoc.data();
      });

      const userArray = await Promise.all(userPromises);
      setUsers(userArray);
      isFetched.current = true;
    } catch (error) {
      console.error("获取收藏用户失败:", error);
    }
  };

  fetchFavUsers();
}, [userUid]); // 仅依赖userUid,避免无限循环

方案2:实时监听用户数据变化

若需要在用户数据更新时自动刷新界面,需正确管理onSnapshot的监听回调,并在组件卸载时清理监听,同时处理状态的增量更新。

import { useEffect, useState, useRef } from 'react';
import { getDocs, query, collection, where, onSnapshot, doc } from 'firebase/firestore';

// ... 组件其他代码
const [users, setUsers] = useState([]);
const unsubscribeRef = useRef([]); // 保存监听取消函数

useEffect(() => {
  const setupFavUserListeners = async () => {
    try {
      // 查询当前用户的收藏列表
      const q = query(
        collection(db, "favoritFreelancer"),
        where("cid", "==", userUid)
      );
      const querySnapshot = await getDocs(q);

      querySnapshot.docs.forEach((favUser) => {
        // 为每个收藏用户添加实时监听
        const unsubscribe = onSnapshot(doc(db, "users", favUser.data().lancerID), (userDoc) => {
          const userData = userDoc.data();
          // 增量更新users状态,避免覆盖已有数据
          setUsers(prevUsers => {
            const updatedUsers = [...prevUsers];
            const existingIndex = updatedUsers.findIndex(u => u.uid === userData.uid);
            if (existingIndex !== -1) {
              updatedUsers[existingIndex] = userData;
            } else {
              updatedUsers.push(userData);
            }
            return updatedUsers;
          });
        });
        unsubscribeRef.current.push(unsubscribe);
      });
    } catch (error) {
      console.error("设置收藏用户监听失败:", error);
    }
  };

  setupFavUserListeners();

  // 组件卸载时清理所有监听
  return () => {
    unsubscribeRef.current.forEach(unsubscribe => unsubscribe());
  };
}, [userUid]);

映射代码修复

原映射代码中第二个条件判断的fullname未指定为user.fullname,会导致报错,修正后代码如下:

<ScrollView style={{ flex: 1 }} className="flex-col w-full">
  {users.map((user) =>
    searchText === "" ? (
      <FreelancerCard
        key={user.uid}
        fullname={user.fullname}
        experience={user.experience}
        stars={user.stars}
        jobs={user.jobs}
        status={user.status}
        categories={user.category}
        contact={user.contact}
        imgUrl={user.profilePic}
      />
    ) : user.fullname.toLowerCase().includes(searchText.toLowerCase()) ? (
      <FreelancerCard
        key={user.uid}
        fullname={user.fullname}
        experience={user.experience}
        stars={user.stars}
        jobs={user.jobs}
        status={user.status}
        categories={user.category}
        contact={user.contact}
        imgUrl={user.profilePic}
      />
    ) : null
  )}
</ScrollView>

验证效果

应用启动重载时,会自动查询并加载收藏的freelancer数据,无需等待热重载即可正常显示界面;同时避免了无限循环问题。

内容的提问来源于stack exchange,提问作者Mariyan Anjelo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 09:15:02