React Native Expo中Firestore onSnapshot函数在iOS端无法正常工作
Expo iOS端Firestore onSnapshot无法触发,Web端正常
问题背景
我尝试在Firestore中实现文档引用的实时更新订阅功能,由于react-native-firestore与Expo不兼容,因此使用官方firebase/firestore库。目前该功能在Expo Web(Chrome)端运行正常,但在Expo iOS端完全无法工作,甚至无法执行到console.log('Current data')语句。
代码示例
onSnapshot(await doc(firestore, "users", user.uid), (doc) => { console.log("Current data"); if (doc.data()) { const oData = { likedMovies: doc.data().likedMovies, dislikedMovies: doc.data().dislikedMovies, matches: doc.data().likedMovies // TODO: change this to matches array } setUserData(oData) } else { setUserData({}) } })
收到的提示
警告

错误

我尝试改成异步形式后,iOS端不再崩溃,但setUserData逻辑始终不执行,或者数据被设为undefined。推测问题和onSnapshot有关,但Web端能正常运行,求解决建议。
解决建议
1. 修复await的错误使用
你在onSnapshot的第一个参数里直接用了await doc(...),这会导致传递给onSnapshot的是Promise对象,而非DocumentReference实例——这是核心问题!Web端可能因兼容逻辑忽略该错误,但iOS端类型校验更严格,直接导致监听失败。
正确写法是先同步获取文档引用,再绑定监听:
// doc方法本身是同步的,无需await const userDocRef = doc(firestore, "users", user.uid); // 绑定监听并添加错误回调 onSnapshot(userDocRef, (doc) => { console.log("Current data"); // 用doc.exists()判断文档是否存在比doc.data()更可靠 if (doc.exists()) { const data = doc.data(); const oData = { likedMovies: data.likedMovies, dislikedMovies: data.dislikedMovies, matches: data.likedMovies // TODO: 替换为matches数组 } setUserData(oData); } else { setUserData({}); } }, (error) => { // 错误回调能帮你快速定位iOS端的问题 console.error("用户文档监听失败:", error); });
2. 修正Firestore权限规则
警告明确提示Missing or insufficient permissions,说明你的安全规则未允许当前用户读取自己的文档。确保规则配置如下:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow read, write: if request.auth != null && request.auth.uid == userId; } } }
该规则仅允许登录用户读写自己的用户文档,符合业务逻辑。
3. 检查Expo iOS端Firebase初始化
Expo iOS端对Firebase初始化有特殊要求,确保遵循官方配置规范:
- 确认
GoogleService-Info.plist已正确导入项目,本地调试或eas build时会自动处理,但需检查配置是否匹配。 - 尽量在App启动时同步初始化Firebase,避免异步延迟:
import { initializeApp } from 'firebase/app'; import { getFirestore } from 'firebase/firestore'; const firebaseConfig = { // 你的Firebase项目配置 }; const app = initializeApp(firebaseConfig); export const firestore = getFirestore(app);
4. 添加监听清理逻辑(避免内存泄漏)
在React组件中使用onSnapshot时,必须在组件卸载时取消监听,否则可能引发iOS端异常:
useEffect(() => { if (!user?.uid) return; const userDocRef = doc(firestore, "users", user.uid); const unsubscribe = onSnapshot(userDocRef, (doc) => { // 你的数据处理逻辑 }, (error) => { console.error("监听失败:", error); }); // 组件卸载时取消监听 return () => unsubscribe(); }, [user?.uid]); // 依赖项添加user.uid,用户ID变化时重新绑定监听
内容的提问来源于stack exchange,提问作者bevan
相关产品推荐
相关产品推荐

