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

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({})
    }
})

收到的提示

警告

Firestore权限不足警告

错误

Firestore文档快照数据调用错误

我尝试改成异步形式后,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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 03:52:33