监听Firestore集合更新Recoil状态时编辑删除文档崩溃怎么办?
问题解决方案
根因
你直接将Firestore doc.data() 返回的对象存入Recoil状态时,该对象仍绑定Firestore SDK内部隐藏引用。Recoil默认会冻结所有状态为只读对象,当你编辑/删除文档触发快照更新时,Firestore SDK尝试修改对象的内部属性就会触发只读报错。新增文档时首次写入没有后续修改操作,因此不会触发异常。
修复步骤
- 对
doc.data()返回的对象做深度拷贝,切断和Firestore SDK的引用关联 - 修正
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
相关产品推荐
相关产品推荐

