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

Next.js中React Context始终取默认值报setName非函数问题排查

错误原因

核心问题是违反React Context的基础使用规则:只有被Context.Provider包裹的后代组件,才能通过hook消费到Provider传入的上下文值,在Provider外层调用Context Hook只会拿到定义Context时设置的默认值。
你的代码里,usePeople()是在MyApp组件顶层调用的,但<PeopleProvider>是MyApp自身return时才渲染的父容器,MyApp本身完全处于Provider的作用域之外,所以拿到的setName、setAge永远是默认值里的null,调用时自然抛出setName is not a function错误。
另外你贴的代码里还有一处语法笔误:setName(name)后多写了一个多余的右括号,修复结构问题时记得一并删除。

修复方案

两种实现都可以正常运行,优先推荐第一种:

  • 方案1:将初始化逻辑内聚到PeopleProvider内部
    这是最合理的实现方式,Context的状态初始化逻辑本来就应该封装在Provider组件内,不需要放到_app层处理。直接修改PeopleProvider的state定义,把环境变量值作为state初始值即可:
// PeopleProvider 组件代码
const peopleContextDefaultValue = {
  name: null,
  age: null,
  setName: null,
  setAge: null,
};

// ...其他逻辑

// 初始化state时直接读取环境变量作为默认值
const [name, setNameState] = useState(process.env.NEXT_PUBLIC_NAME || null);
const [age, setAgeState] = useState(process.env.NEXT_PUBLIC_AGE ? Number(process.env.NEXT_PUBLIC_AGE) : null);

const setName = (payload) => {
  setNameState(payload);
};

const setAge = (payload) => {
  setAgeState(payload);
};

const value = {
  name,
  age,
  setName,
  setAge,
};

return (
  <PeopleContext.Provider value={value}>
    {children}
  </PeopleContext.Provider>
);

改完后_app.js里不需要再写那段useEffect逻辑,直接渲染Provider包裹路由组件即可:

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <PeopleProvider>
      <Navbar />
      <Component {...pageProps} />
    </PeopleProvider>
  );
}

export default MyApp;

这种写法的优势是不需要等useEffect执行再赋值,首屏渲染时Context就已经持有正确的初始值,不会出现状态短暂为null的闪烁问题,代码逻辑也更内聚好维护。

  • 方案2:抽离子组件承载初始化逻辑
    如果因为特殊需求必须把初始化逻辑写在_app层,就不能在MyApp顶层直接调用usePeople,需要把消费Context、执行初始化的逻辑拆成独立子组件,放到PeopleProvider的内部渲染:
// 单独抽离初始化组件,作为Provider的后代节点可以正常消费Context
function ContextInit() {
  const { setName, setAge } = usePeople();

  useEffect(() => {
    const name = process.env.NEXT_PUBLIC_NAME;
    const age = process.env.NEXT_PUBLIC_AGE;

    if (name) {
      setName(name)
    }

    if (age) {
      setAge(age)
    }
  }, [setName, setAge]);

  return null;
}

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <PeopleProvider>
      <ContextInit />
      <Navbar />
      <Component {...pageProps} />
    </PeopleProvider>
  );
}

export default MyApp;

注意这种方案是在客户端useEffect触发后才给Context赋值,首屏首次渲染时Context的name、age还是null,如果页面组件首屏就依赖这两个值做渲染/逻辑判断,会出现短暂的空值状态,非必要不选这个方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 19:45:58