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

React Firebase onSnapshot自定义函数行为不一致问题咨询

问题描述

使用Next.js框架,通过Firebase的onSnapshot方法获取数据,自定义函数warningEmptyData用于在数据为空时弹出模态框,出现以下不一致行为:

  • 场景:初始数据为空,组件首次挂载后数据无任何变更
  • 在onSnapshot回调内(位置1️⃣)调用warningEmptyData:模态框仅显示一次
  • 在useEffect的清理函数内(位置2️⃣)调用:模态框显示两次
    已知可能与useState变更引发的重渲染有关,但依赖数组已设为[]且无数据变更,对此存在疑问。

相关代码:

const [listData, setListData] = useState()
...
useEffect(() => {
    const queryLists = query(
      // 查询相关代码
    );

    const fetchLists = onSnapshot(queryLists, (snapshot) => {
      const datas = snapshot.docs.map((doc) => doc.data());
      setListsData(datas);
      warningEmptyData(datas); // 1️⃣
    });
    
    const warningEmptyData = (data: any[]) => {
      if (data.length < 1) {
        Modal.warning({
          // 警告框内容代码
        });
      }
    };
    return () => {
      fetchLists();
      warningEmptyData(datas); // 2️⃣
  }, []);
原因分析
  1. 开发环境下Strict Mode的重复执行
    Next.js在开发环境默认开启React Strict Mode,它会刻意重复执行组件的挂载、卸载流程——也就是useEffect会被执行两次:第一次挂载后立即卸载(触发清理函数),然后再次挂载。这直接导致你的清理函数被调用两次,每次调用都会触发warningEmptyData弹出模态框,所以最终显示两次。

  2. 变量引用的闭包问题
    你的代码里存在一个明显错误:清理函数中的datas是未定义的(它只存在于onSnapshot回调的局部作用域)。如果实际是想传入listData,由于useEffect依赖数组为[],清理函数捕获的是listData的初始值undefined,此时调用warningEmptyData(undefined)会触发data.length的报错,但你看到模态框弹出两次,说明你大概率是误写了变量名(比如实际传入的是一个空数组),再加上Strict Mode的重复执行,就出现了两次弹窗。

  3. onSnapshot的回调逻辑
    位置1️⃣的调用仅触发一次是正常的:onSnapshot在首次获取到数据后触发回调,后续没有数据变更时不会再次执行,所以warningEmptyData只被调用一次,模态框仅显示一次。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 07:03:14