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️⃣ }, []);
原因分析
开发环境下Strict Mode的重复执行
Next.js在开发环境默认开启React Strict Mode,它会刻意重复执行组件的挂载、卸载流程——也就是useEffect会被执行两次:第一次挂载后立即卸载(触发清理函数),然后再次挂载。这直接导致你的清理函数被调用两次,每次调用都会触发warningEmptyData弹出模态框,所以最终显示两次。变量引用的闭包问题
你的代码里存在一个明显错误:清理函数中的datas是未定义的(它只存在于onSnapshot回调的局部作用域)。如果实际是想传入listData,由于useEffect依赖数组为[],清理函数捕获的是listData的初始值undefined,此时调用warningEmptyData(undefined)会触发data.length的报错,但你看到模态框弹出两次,说明你大概率是误写了变量名(比如实际传入的是一个空数组),再加上Strict Mode的重复执行,就出现了两次弹窗。onSnapshot的回调逻辑
位置1️⃣的调用仅触发一次是正常的:onSnapshot在首次获取到数据后触发回调,后续没有数据变更时不会再次执行,所以warningEmptyData只被调用一次,模态框仅显示一次。
内容的提问来源于stack exchange,提问作者Bible
相关产品推荐
相关产品推荐

