如何将React中Firestore集合组查询代码转换为实时数据读取?onSnapshot调用报错解决方案
解决Firestore集合组查询onSnapshot的错误问题
你碰到的catch is not a function错误,核心原因是**onSnapshot和get()的调用逻辑完全不同**:get()返回Promise,所以可以用.then().catch()链式处理;但onSnapshot是通过回调监听实时更新,错误要通过它的第二个参数(错误回调)捕获,而且它返回的是一个取消订阅的函数,根本没有.catch()方法,自然会报错。
另外在React的useEffect里用onSnapshot,一定要记得在组件卸载时取消订阅,不然会造成内存泄漏,这个细节很容易忽略。
下面是修改后的完整可运行代码:
useEffect(() => { setLoading(true); const date = new Date(); const januari = new Date(date.getFullYear(), 0); const juni = new Date(date.getFullYear(), 5 + 1, 0); const tahunSekarang = date.getFullYear(); const tahunSetelah = date.getFullYear() + 1; const tahunSebelum = date.getFullYear() - 1; const pengunjungRef = firebase .firestore() .doc( date >= januari && date <= juni ? 'pengunjung/genap' : 'pengunjung/ganjil' ); // 单独提取集合组名称,让代码更清晰 const collectionGroupName = date >= januari && date <= juni ? `${tahunSebelum}_${tahunSekarang}` : `${tahunSekarang}_${tahunSetelah}`; // 订阅实时更新,保存取消订阅的函数 const unsubscribe = firebase .firestore() .collectionGroup(collectionGroupName) .orderBy(firebase.firestore.FieldPath.documentId()) .startAt(pengunjungRef.path) .endAt(pengunjungRef.path + '\uf8ff') .onSnapshot( // 数据更新的成功回调 (querySnapshot) => { let list = []; querySnapshot.forEach((doc) => { list.push({ id: doc.id, ...doc.data() }); }); setData(list); setLoading(false); }, // 错误处理回调 (err) => { console.error('failed to execute query', err); setLoading(false); } ); // 组件卸载时取消监听,避免内存泄漏 return () => unsubscribe(); }, []);
关键修改点说明:
- 把错误处理逻辑从
.catch()移到了onSnapshot的第二个参数中,这是Firestore实时监听的标准错误处理方式 - 保存
onSnapshot返回的unsubscribe函数,在useEffect的返回值中调用,确保组件销毁时停止监听 - 单独提取集合组名称,让代码结构更清晰,便于后续维护
这样修改后,你的数据表格就能实时同步Firestore集合组的更新了,同时也能正确处理查询错误,还避免了内存泄漏的风险。
内容的提问来源于stack exchange,提问作者Gie
相关产品推荐
相关产品推荐

