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

ReactJS从Firebase/Firestore渲染用户数据异常问题排查

React + Firestore 数据渲染异常修复方案

问题现象

  • 初始加载或修改代码后,表格显示所有用户的全部文档数据,仅刷新页面后才展示当前登录用户的数据
  • 添加新值时,表格显示全部数据且当前用户数据重复,刷新后恢复正常

核心问题

  • 错误监听了整个data集合,而非当前用户的单个文档,导致拉取所有用户数据
  • 快照回调中未重置数据数组,新增数据时重复累加旧内容
  • 未清理onAuthStateChanged和onSnapshot的监听,引发重复订阅问题

修复后的完整代码

export default function Nutrition() {
  const [data, setData] = useState([]);

  useEffect(() => {
    let unsubscribeAuth;
    let unsubscribeSnapshot;

    unsubscribeAuth = onAuthStateChanged(auth, async (user) => {
      if (user) {
        const uid = user.uid;
        const userDocRef = doc(db, "data", uid);
        
        // 校验用户文档是否存在
        const initialSnapshot = await getDoc(userDocRef);
        if (initialSnapshot.exists()) {
          // 仅监听当前用户的文档变化,而非整个集合
          unsubscribeSnapshot = onSnapshot(userDocRef, (docSnapshot) => {
            const { value, quantity } = docSnapshot.data();
            // 每次快照触发时重置数组,避免重复累加
            const foods = [];
            // 处理空数组情况,防止报错
            const dataLength = value?.length || 0;
            for (let i = 0; i < dataLength; i++) {
              foods.push({ 
                value: value[i], 
                quantity: quantity[i],
                id: `${uid}-${i}` // 生成唯一key,避免React渲染警告
              });
            }
            setData(foods);
          });
        } else {
          console.log("用户文档不存在");
          setData([]);
        }
      } else {
        console.log("用户未登录");
        setData([]);
        // 用户登出时清理快照监听
        if (unsubscribeSnapshot) unsubscribeSnapshot();
      }
    });

    // 组件卸载时清理所有监听,防止内存泄漏
    return () => {
      if (unsubscribeAuth) unsubscribeAuth();
      if (unsubscribeSnapshot) unsubscribeSnapshot();
    };
  }, []);

  return (
    <React.Fragment>
      <div className='container mt-3'>
        <table className='table table-hover'>
          <thead>
            <tr>
              <th>#</th>
              <th>食物</th>
              <th>数量</th>
            </tr>
          </thead>
          <tbody>
            {data.map((row, index) => (
              <tr key={row.id}>
                <td>{index + 1}</td>
                <td>{row.value}</td>
                <td>{row.quantity}</td>
              </tr>
            ))}
          </tbody>
        </table>
        <button className='btn btn-dark mt-3'>重置表格</button>
      </div>
    </React.Fragment>
  );
}

关键修复说明

  • 精准数据监听:将onSnapshot的监听目标从整个data集合改为当前用户的单个文档userDocRef,确保只获取当前用户的私有数据
  • 数据重置机制:每次快照回调时重新初始化foods数组,彻底解决重复累加问题
  • 监听生命周期管理:在组件卸载和用户登出时清理所有订阅,避免内存泄漏和重复触发
  • 唯一key优化:为每个表格行项生成唯一id,消除React列表渲染的key警告

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 02:01:19