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

监听Firestore集合更新Recoil状态时编辑删除文档崩溃怎么办?

问题解决方案

根因

你直接将Firestore doc.data() 返回的对象存入Recoil状态时,该对象仍绑定Firestore SDK内部隐藏引用。Recoil默认会冻结所有状态为只读对象,当你编辑/删除文档触发快照更新时,Firestore SDK尝试修改对象的内部属性就会触发只读报错。新增文档时首次写入没有后续修改操作,因此不会触发异常。

修复步骤

  1. 对doc.data()返回的对象做深度拷贝,切断和Firestore SDK的引用关联
  2. 修正onSnapshot错误回调的传参位置,你之前的错误回调写在了forEach的参数中,属于无效写法,无法捕获监听异常

修复后代码

useEffect(() => {
  getPos();
  const q = query(collection(getFirestore(), "activities"));
  const unsub = onSnapshot(q, (querySnapshot) => {
    const activitiesArr: any = [];
    querySnapshot.forEach((doc) => {
      // 深度拷贝数据,移除Firestore内部绑定属性
      const pureDocData = structuredClone(doc.data());
      activitiesArr.push({ ...pureDocData, id: doc.id });
    });
    setActivities(activitiesArr);
  }, (error: Error) => {
    // 错误回调放在onSnapshot的第二个参数位置才能正常捕获监听异常
    console.log(error);
  });

  return () => unsub();
}, []);

如果运行环境不支持structuredClone,可以替换为JSON.parse(JSON.stringify(doc.data()))实现深拷贝。

备选方案(不推荐)

如果你不想做深拷贝,也可以在定义activities对应的Recoil atom时,添加dangerouslyAllowMutability: true配置关闭状态冻结,但该方案会失去Recoil的不可变状态保护,可能出现意外修改状态导致的bug。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 15:39:04