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

React Native接收SSE流数据时state未自动更新问题求助

问题根本原因

1. 闭包捕获了陈旧变量值

你将RNEventSource实例声明在了组件外部,startListenStatus中添加的消息回调函数,捕获的是组件首次渲染时的user、updateStatus等变量的引用。当用户从页面2跳转回页面1、组件发生重渲染后,回调函数里拿到的还是第一次渲染时的旧值:比如此时user.accountID已经更新为当前用户的真实ID,但回调里的user还是初始的空值/旧值,自然parsedData.account_id === user.accountID的条件判断无法命中。
你硬刷新Expo应用后,所有变量重新初始化,回调捕获的就是最新的正确值,所以逻辑可以正常执行。

2. useEffect依赖项不全

你第一个初始化用的useEffect依赖设置为空数组,仅会在组件首次挂载时执行一次,如果后续route.params.eventListen发生变化也不会触发逻辑更新;监听accountStatus的useEffect也没有把startListenStatus、stopListenStatus加入依赖,容易出现逻辑异常。

3. 全局SSE实例复用异常

全局复用同一个SSE实例,如果上次页面卸载时没有完全清理连接和监听,下次进入页面时添加的新监听会和旧监听冲突,也会导致逻辑不生效。


修复方案

  1. 把SSE实例的创建移到组件内部,每次进入pending状态时新建连接,不要复用全局实例
  2. 用useRef存储最新的user等变量,避免闭包陷阱
  3. 补全所有useEffect的依赖项,组件卸载时强制清理SSE连接和监听

核心修改后的代码示例

export default function AccountRegister({ navigation, getUser, user, route}) {
  const [ accountStatus, setAccountStatus ] = useState();
  const sseRef = useRef(null);
  // 用ref存最新的user,避免闭包拿旧值
  const userRef = useRef(user);
  useEffect(() => {
    userRef.current = user;
  }, [user]);

  const startListenStatus = () => {
    // 每次启动监听时新建SSE实例
    const sse = new RNEventSource('Third party URL', {
      headers: {
        'Accept': 'text/event-stream',
        'Authorization' : 'token'
      }
    });
    sseRef.current = sse;

    sse.addEventListener('message', (event) => {
      const parsedData = JSON.parse(event.data);
      console.log('listening..');
      // 从ref里拿最新的user
      if (parsedData.account_id === userRef.current.accountID) {
        console.log('found account');
        if (parsedData.status_to === 'ACTIVE') {
          updateStatus('ACTIVE');
        }
      }
    });
  }

  const stopListenStatus = () => {
    if (sseRef.current) {
      sseRef.current.removeAllListeners();
      sseRef.current.close();
      sseRef.current = null;
    }
    getUser();
    navigation.setParams({eventListen: false});
    console.log('stopped listen');
  }

  // 补全依赖
  useEffect(() => {
    if ((route.params && route.params.eventListen)){
      updateStatus('PENDING');
    } else {
      getStatus();
    }
  },[route.params, getStatus, updateStatus])

  useEffect(() => {
    if (accountStatus === 'PENDING') {
      startListenStatus();
    } else if (accountStatus === 'ACTIVE') {
      stopListenStatus();
    }
    // 组件卸载时清理连接避免内存泄漏
    return () => {
      if (sseRef.current) {
        sseRef.current.removeAllListeners();
        sseRef.current.close();
      }
    }
  },[accountStatus, startListenStatus, stopListenStatus])

  // updateStatus、getStatus、渲染逻辑和原有代码保持一致即可
  // ...
}

内容的提问来源于stack exchange,提问作者Joon Joonam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 23:09:02