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

React useContext状态更新未触发useEffect问题求助

React useContext状态更新未触发useEffect问题求助

兄弟,我一眼就看到你代码里最核心的问题了——你把LicenseContextProvider放错位置啦! 这直接导致你的LandingPage根本没在Provider的上下文范围内,所以状态更新完全传不到组件里,自然也触发不了useEffect。

问题根源分析

你现在的LandingPage组件逻辑是:先调用useLicense()获取上下文,然后在自己的JSX里渲染LicenseContextProvider。但React组件的执行顺序是先跑组件逻辑(包括useLicense()),再渲染JSX。这就意味着:

  1. 当useLicense()执行时,LicenseContextProvider还没被渲染,所以useContext拿到的是你初始化createContext时的默认空对象(你用了{} as LicenseContextModel强制类型断言,所以是空对象)。
  2. 后面LicenseContextProvider内部的状态更新,只会影响它包裹的子组件,但LandingPage本身不在这个Provider的范围内,所以状态更新和它完全没关系。

看你控制台的日志也能佐证这一点:一开始context是空对象,page isLoading是undefined,而Provider内部的licenseContext明明已经更新了,但就是传不到LandingPage里。

修复步骤

1. 把Provider移到全局或父组件(Next.js推荐在_app.tsx配置)

因为你用的是Next.js,最合理的做法是在全局的_app.tsx里用LicenseContextProvider包裹整个应用,这样所有页面都能共享上下文:

// _app.tsx
import type { AppProps } from 'next/app'
import LicenseContextProvider from '@/contexts/license-context'

export default function App({ Component, pageProps }: AppProps) {
  return (
    <LicenseContextProvider>
      <Component {...pageProps} />
    </LicenseContextProvider>
  )
}

2. 修改LandingPage,移除内部的Provider

现在LandingPage已经在全局Provider的范围内了,直接用useLicense()就行,不需要自己嵌套Provider:

// LandingPage.tsx
import React, { useEffect } from "react";
import { useLicense } from '@/contexts/license-context';
import { useRouter } from 'next/navigation';

const LandingPage = () => {
  const { product, api, isLoading } = useLicense();
  const router = useRouter();

  useEffect(() => {
      console.log('page isLoading', isLoading);
      
      if (!isLoading) {
        console.log('product', product);
        console.log('api', api);
  
        if (!product) {
          router.push('/license-warning');
        } else if (!api) { // 这里改成!api更贴合你的初始值逻辑
          router.push('/key-manager');
        }
      }
    },[product, api, isLoading]);
  
  return (
    <>
      <title>Landing Page</title>
      <div className="w-full">
        <div className="flex flex-col w-full">
          <p>Landed on the page</p>
        </div>
      </div>
    </>
  );
};

export default LandingPage;

3. 优化上下文初始化(可选但推荐)

你现在用{} as LicenseContextModel强制断言默认上下文,类型不够安全。可以改成:

// license-context.tsx
export const LicenseContext = createContext<LicenseContextModel | undefined>(undefined);

export function useLicense(): LicenseContextModel {
    const context = useContext(LicenseContext);
    if (!context) {
        throw new Error('useLicense must be used within a LicenseContextProvider');
    }
    return context;
}

这样如果不小心在Provider外调用useLicense(),会直接抛出明确的错误,更容易排查问题。

修复后效果

修改完成后,LandingPage会正确获取Provider的上下文状态,当Provider里的isLoading、product、api更新时,组件的useEffect会被正确触发,路由跳转逻辑也能正常工作。

备注:内容来源于stack exchange,提问作者JediPotPie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 08:45:35