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

useEffect依赖react-navigation的useIsFocused时setState不生效

问题根因

两个核心错误导致状态不更新:

  • 违反React状态不可变更新原则:代码里const newRoute = route;仅复制了状态对象的引用地址,没有创建全新的对象/数组副本,后续直接修改newRoute.visitas本质是在直接修改原state。最终调用setRoute(newRoute)时,React对state做浅比较发现传入的引用和当前state的引用完全一致,会判定状态没有变化,跳过重渲染和对应useEffect的触发。这也是为什么setIsLoading(true)能正常执行——它在副作用函数运行时就被直接调用,不需要等状态变更检测,但监听route的副作用里的setIsLoading(false)因为状态更新被跳过永远不会执行,最终页面卡在加载态。
  • 副作用依赖缺失:监听isFocused的useEffect内部使用了route、myRoute.params等外部值,但依赖数组仅传入了isFocused,闭包会长期缓存首次渲染时的空route对象,不仅会导致访问newRoute.visitas时抛出异常,也会导致状态更新逻辑拿到的值始终是过期的旧值。
修复方案
  1. 所有状态更新必须做不可变拷贝,嵌套对象/数组要逐层生成新的引用
  2. 补全useEffect的依赖项,或者使用函数式更新拿到最新的state值,避免闭包过期问题
  3. 页面聚焦触发更新的逻辑优先使用useFocusEffect实现,比useIsFocused配合普通useEffect的写法更符合react-navigation的设计规范

修复后的核心代码:

import React, { useEffect, useState, useCallback } from 'react';
import { useFocusEffect } from '@react-navigation/native';

const MyRoute = ({ navigation, route: myRoute }) => {
  const [route, setRoute] = useState({});
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    console.log('route call')
    if (Object.keys(route).length) {
      setIsLoading(false);
    }
  }, [route]);

  useEffect(() => {
    console.log(isLoading);
  }, [isLoading]);

  // 用useFocusEffect替代监听isFocused的普通useEffect
  useFocusEffect(
    useCallback(() => {
      if (myRoute.params?.isChecked) {
        setIsLoading(true);
        // 函数式更新拿到最新的route状态,同时做逐层拷贝生成新引用
        setRoute(oldRoute => {
          const newRoute = {
            ...oldRoute,
            visitas: oldRoute.visitas.map(item => {
              if (item.sub_id === myRoute.params.sub_id) {
                return {
                  ...item,
                  realizada: true,
                  check_in_out: myRoute.params.check_in_out
                }
              }
              return item;
            })
          };
          return newRoute;
        });
      }
    }, [myRoute.params])
  );

  /** ... */
}

注意:不要用JSON.parse(JSON.stringify(route))这种暴力深拷贝的方式处理状态,如果对象里有函数、undefined、Date等类型值会出现异常,逐层展开拷贝或者用Immer这类不可变更新库更稳妥。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 05:45:40