多个Firestore onSnapshot绑定单个setState出现数据覆盖问题求解
问题根因
该问题属于React函数组件的闭包陷阱:你的useEffect依赖项仅包含user.id,所有onSnapshot回调捕获的都是effect执行时对应渲染周期的itemsByUser值(初始为空对象)。每次回调触发执行状态更新时,都是基于旧的空对象做扩展,因此会覆盖之前其他回调写入的数据。
解决方案
- 改用setState的函数式更新写法
函数式更新可以直接获取最新的state快照,不需要依赖外层作用域的state变量,将所有setItemsByUser调用改为函数式写法即可解决覆盖问题。
- 改用setState的函数式更新写法
- 补全useEffect的依赖项
当前依赖列表未包含users,如果后续关注用户列表发生变化,effect不会重新执行,无法给新关注用户添加监听,也不会清理已取消关注用户的监听,需要把users加入依赖数组。
- 补全useEffect的依赖项
修改后完整代码
useEffect(() => { if (user.id) { let subscribers = []; const mainSubscriber = db .collection('Events') .doc(user.id) .collection('following') .onSnapshot(snapshot => { const docs = snapshot.docs.map(d => d.data()); const events = formatEvents(docs); // 函数式更新获取最新状态 setItemsByUser(prev => ({...prev, [user.id]: events})); }); subscribers.push(mainSubscriber); if (users && users.length) { for (const u of users) { const sub = db .collection('Events') .doc(u.id) .collection('followers') .onSnapshot(snap => { const docs = snap.docs.map(d => d.data()); const events = formatEvents(docs); if (docs.length) { // 函数式更新获取最新状态 setItemsByUser(prev => ({...prev, [u.id]: events})); } }); subscribers.push(sub); } } return () => subscribers.forEach(sub => sub()); } // 补全users依赖 }, [user.id, users]);
优化建议
如果关注的用户数量较多,大量的实时监听可能会引发性能问题,可考虑在服务端做聚合逻辑,一次性返回当前用户和所有关注用户的活动数据,减少监听数量。
内容的提问来源于stack exchange,提问作者Jonathan Jeshua Laniba
相关产品推荐
相关产品推荐

