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

Expo集成Firebase跨屏幕数据存储问题求助

嘿,我来帮你搞定这两个问题!咱们一个个来拆解:

问题1:经纬度没存入当前用户的users节点下

你现在的更新代码是直接对users/根节点执行update,这会把经纬度数据添加到users节点本身,而不是当前登录用户的UID子节点里。要解决这个,得先拿到当前登录用户的UID,然后定位到对应的路径。

解决方案:

首先,获取当前登录的Firebase用户,然后针对其UID节点做更新。你可以把更新逻辑放在位置变化的回调里(也就是watchPosition的第一个参数里),这样每次位置更新时,都会同步到Firebase:

修改你componentDidMount里的位置监听部分:

const watchId = navigator.geolocation.watchPosition(
  ({ coords: { latitude, longitude } }) => {
    this.setState({ latitude, longitude }, () => {
      // 状态更新完成后,同步到Firebase
      const currentUser = firebase.auth().currentUser;
      if (currentUser) {
        // 定位到当前用户的节点
        firebase.database().ref(`users/${currentUser.uid}`).update({
          latitude,
          longitude
        }).then(() => {
          console.log("经纬度已成功更新到Firebase");
        }).catch(err => {
          console.error("更新失败:", err);
        });
      } else {
        console.log("当前没有登录用户,无法更新位置");
      }
    });
  },
  (error) => this.setState({ error: error.message }),
  { enableHighAccuracy: true, timeout: 0, maximumAge: 1000, distanceFilter: 1 },
);

这样一来,每次位置变化时,都会把经纬度存入users/[当前用户UID]节点下,而不是users根节点啦。

问题2:“无法在已卸载组件调用setState”错误

这个错误的原因是:当你的主屏幕组件被卸载(比如用户跳转到其他页面)后,geolocation.watchPosition还在持续监听位置变化,这时回调里的this.setState会尝试更新一个已经不存在的组件状态,所以就报错了。另外你代码里还有个小bug:catch块里的变量是err,但你打印的是error,这会导致控制台输出undefined。

解决方案:

  1. 在组件卸载时清除位置监听
    给你的主屏幕组件添加componentWillUnmount生命周期方法,用来清理位置监听:
async componentWillUnmount() {
  // 从AsyncStorage里取出之前保存的watchId
  const watchId = await AsyncStorage.getItem('LiveFeedId');
  if (watchId) {
    // 清除位置监听
    navigator.geolocation.clearWatch(JSON.parse(watchId));
    // 删除保存的watchId
    await AsyncStorage.removeItem('LiveFeedId');
  }
}
  1. 修复catch块的变量错误
    把console.error(error);改成console.error(err);,不然会出现error is not defined的额外错误。

  2. 额外优化:避免重复监听
    在启动新的位置监听前,先检查是否已有旧的监听存在并清除,这样更健壮:

修改后的完整componentDidMount代码:

async componentDidMount() {
  try {
    let { status } = await Permissions.getAsync(Permissions.LOCATION);
    if (status !== 'granted') {
      const { status: newStatus } = await Permissions.askAsync(Permissions.LOCATION);
      if (newStatus !== 'granted') {
        this.setState({ error: "位置权限未获取,无法更新位置信息" });
        return;
      }
    }

    // 先清除可能存在的旧监听
    const oldWatchId = await AsyncStorage.getItem('LiveFeedId');
    if (oldWatchId) {
      navigator.geolocation.clearWatch(JSON.parse(oldWatchId));
    }

    const watchId = navigator.geolocation.watchPosition(
      ({ coords: { latitude, longitude } }) => {
        this.setState({ latitude, longitude }, () => {
          const currentUser = firebase.auth().currentUser;
          if (currentUser) {
            firebase.database().ref(`users/${currentUser.uid}`).update({
              latitude,
              longitude
            }).catch(err => console.error("更新位置到Firebase失败:", err));
          }
        });
      },
      (error) => this.setState({ error: error.message }),
      { enableHighAccuracy: true, timeout: 0, maximumAge: 1000, distanceFilter: 1 },
    );

    await AsyncStorage.setItem('LiveFeedId', JSON.stringify(watchId));
  } catch (err) {
    console.error("获取位置权限失败:", err);
    this.setState({ error: err.message });
  }
}

额外提醒:

为了确保主屏幕组件只有在用户登录时才执行定位逻辑,你还可以添加Firebase auth状态监听,避免用户未登录时出现错误:

componentDidMount() {
  // 监听用户登录状态
  this.authUnsubscribe = firebase.auth().onAuthStateChanged(user => {
    if (user) {
      // 用户已登录,初始化定位追踪
      this.initLocationTracking();
    } else {
      // 用户未登录,跳转到登录页
      this.props.navigation.navigate('Login');
    }
  });
}

componentWillUnmount() {
  // 取消auth状态监听
  if (this.authUnsubscribe) {
    this.authUnsubscribe();
  }
  // 清除位置监听
  // ...之前的清除代码
}

// 把定位逻辑抽成单独方法
async initLocationTracking() {
  // 这里放之前的定位权限和监听代码
}

这样调整后,两个问题应该都能解决啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:54:47