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

React路由切换时useEffect触发但未更新状态,自定义Hook数据正常问题排查

问题原因
  1. useEffect依赖项不符合规则:你当前的useEffect仅将customers加入依赖数组,但内部逻辑实际用到了user和keycloak两个变量。路由切换后组件重新挂载时,customers可能先于user、keycloak加载完成,此时触发useEffect时user?.email为undefined,过滤得到的filteredCustomers是空数组;后续user、keycloak初始化完成后,因为没有被加入依赖数组,useEffect不会重新执行,状态就会一直保留为空。刷新页面时user、keycloak往往已经提前完成初始化,所以过滤逻辑可以正常执行。
  2. 异步请求存在竞态问题:useEffect内部的Promise.all没有添加取消逻辑,路由切换组件卸载后,未完成的请求在返回后依然会调用setLoans,可能引发内存泄漏或状态错乱。
修复方案

补全useEffect的依赖项,同时添加组件挂载状态判断避免卸载后更新状态,参考代码如下:

export const Overview: React.FC<OverviewProps> = ({ user }) => {
  const { keycloak } = useKeycloak()
  const { state } = useContext(DashboardContext)
  const [customers] = useLoanCustomers(state.contents.date)
  const [userCustomers, setUserCustomers] = useState<DwCustomerHeadline[]>([])
  const [loans, setLoans] = useState<DwLoanContract[]>([])

  useEffect(() => {
    // 标记当前组件挂载状态
    let isMounted = true
    // 依赖未就绪时不执行逻辑
    if (!user?.email || !keycloak) return

    const filteredCustomers = customers.filter((customer) => customer.stafferEmail === user.email)
    setUserCustomers(filteredCustomers)

    Promise.all(
      filteredCustomers.map((customer) => getCustomerLoans(keycloak, customer.counterpartyId))
    ).then((res) => {
      // 仅组件未卸载时更新状态
      if (isMounted) {
        setLoans(res.flat())
      }
    })

    // 组件卸载时标记为已卸载
    return () => {
      isMounted = false
    }
  // 补全所有内部用到的依赖
  }, [customers, user, keycloak])

  // 其余渲染逻辑保持不变
  return (
    <>
      <div className="grid gap-4 p-2 md:grid-cols-3 sm:grid-cols-1">
        <div className="col-span-2 shadow-sm">
          <KeyMetrics />
        </div>
        <div className="shadow-sm">
          <NextReview customers={userCustomers} />
        </div>
      </div>
      <div className="grid gap-4 p-2 md:grid-cols-3 sm:grid-cols-1 grid-rows-2">
        <div className="md:h-80 col-span-2 shadow-sm">
          <ErpOverview customers={userCustomers} />
        </div>
        <div className="row-span-2 shadow-sm" style={{ height: '34rem' }}>
          <Outflow loans={loans} endDate={state.contents.date} />
        </div>
        <div className="h-52 col-span-2 shadow-sm">
          <LoanArrears customers={userCustomers} />
        </div>
      </div>
    </>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 14:45:03