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

React Context报错:无法解构undefined的setAppState属性

React App Context 未定义错误排查

我正在配置全局App Context时遇到了一个难以排查的错误,查阅相关问题后仍无法解决。报错显示AppContext返回undefined,具体错误信息如下:

TypeError: Cannot destructure property 'setAppState' of '(0 , react__WEBPACK_IMPORTED_MODULE_0__.useContext)(...)' as it is undefined.


相关代码文件

appContext.js

import React, { createContext } from 'react';

const AppContext = createContext();

export default AppContext;

appReducer.js

const AppReducer = (state, action) => {
  switch (action.type) {
    case 'SET_APP_STATE':
      return {
        ...state,
        openCities: [...action.payload.openCities],
      };

    default:
      return {
        ...state,
      };
  }
};

export default AppReducer;

appState.js

import React, { useMemo, useReducer } from 'react';
import AppContext from './appContext';
import AppReducer from './appReducer';

const AppState = (props) => {
  const initialState = {
    openCities: [],
  };

  const [state, dispatch] = useReducer(AppReducer, initialState);

  async function setAppState(payload) {
    dispatch({
      type: 'SET_APP_STATE',
      payload,
    });
  }

  return (
    <AppContext.Provider
      value={{
        openCities: state?.openCities,
        setAppState,
      }}
    >
      {props.children}
    </AppContext.Provider>
  );
};

export default AppState;

setOpenCitiesContext.js

import { useContext, useEffect } from 'react';
import AppContext from '../context/appContext/appContext';
import getOpenCities from '../services/city/getOpenCities';
const setOpenCitiesContext = () => {
  const { setAppState } = useContext(AppContext);
  useEffect(() => {
    fetchOpenCities();
  }, []);

  const fetchOpenCities = async () => {
    const openCities = await getOpenCities();

    setAppState(openCities.cities);
  };
};

export default setOpenCitiesContext;

app.js

import React, { useEffect } from 'react';
import TagManager from 'react-gtm-module';
import '../font/font.css';
import '../styles/globals.css';
import '../fonts/fonts.css';
import '../styles/custom.css';
import { CookiesProvider } from 'react-cookie';
import AppState from '../context/appContext/appState';
import UserState from '../context/UserState';
import Amplify from 'aws-amplify';
import awsconfig from '../public/aws-exports';
import NProgress from 'nprogress';
import Router from 'next/router';
import 'nprogress/nprogress.css';
import { GiveawayBanner } from '../components/staticStorefront/GiveawayBanner';
import setOpenCitiesContext from '../utils/setOpenCitiesContext';
Amplify.configure(awsconfig);

const tagManagerArgs = {
  gtmId: 'GTM-KBTCTKD',
};

function MyApp({ Component, pageProps }) {
  setOpenCitiesContext();
  NProgress.configure({
    minimum: 0.3,
    easing: 'ease',
    speed: 800,
    showSpinner: false,
  });

  Router.events.on('routeChangeStart', () => NProgress.start());
  Router.events.on('routeChangeComplete', () => NProgress.done());
  Router.events.on('routeChangeError', () => NProgress.done());

  useEffect(() => {
    TagManager.initialize(tagManagerArgs);
  }, []);

  return (
    <CookiesProvider>
      <AppState>
        <UserState>
          {/* <GiveawayBanner /> */}
          <Component {...pageProps} />
        </UserState>
      </AppState>
    </CookiesProvider>
  );
}

问题根源

  1. 调用时机错误:在MyApp组件顶层直接调用setOpenCitiesContext时,组件还未渲染到AppState Provider内部,useContext(AppContext)会返回默认值(创建Context时未传默认值,因此是undefined)。
  2. 违反Hook规则:setOpenCitiesContext使用了React Hook,但命名未以use开头,也未在组件或其他自定义Hook中调用,不符合React Hook的使用规范。

修复步骤

方案一:修正自定义Hook并在Provider内调用

  1. 重命名并修正Hook文件(useSetOpenCitiesContext.js):
import { useContext, useEffect } from 'react';
import AppContext from '../context/appContext/appContext';
import getOpenCities from '../services/city/getOpenCities';

// 自定义Hook必须以use开头
const useSetOpenCitiesContext = () => {
  const { setAppState } = useContext(AppContext);
  
  useEffect(() => {
    const fetchOpenCities = async () => {
      const openCities = await getOpenCities();
      // 匹配Reducer期望的payload结构
      setAppState({ openCities: openCities.cities });
    };
    
    fetchOpenCities();
  }, [setAppState]);
};

export default useSetOpenCitiesContext;
  1. 在app.js的Provider范围内添加初始化组件:
// app.js 修改部分
import useSetOpenCitiesContext from '../utils/useSetOpenCitiesContext';

function MyApp({ Component, pageProps }) {
  // 移除原有的setOpenCitiesContext()调用
  NProgress.configure({
    minimum: 0.3,
    easing: 'ease',
    speed: 800,
    showSpinner: false,
  });

  Router.events.on('routeChangeStart', () => NProgress.start());
  Router.events.on('routeChangeComplete', () => NProgress.done());
  Router.events.on('routeChangeError', () => NProgress.done());

  useEffect(() => {
    TagManager.initialize(tagManagerArgs);
  }, []);

  return (
    <CookiesProvider>
      <AppState>
        <UserState>
          {/* 在Provider内部调用Hook */}
          <InitializeOpenCities />
          <Component {...pageProps} />
        </UserState>
      </AppState>
    </CookiesProvider>
  );
}

// 专门用于初始化的组件
function InitializeOpenCities() {
  useSetOpenCitiesContext();
  return null;
}

方案二:在AppState内部封装初始化逻辑

直接在appState.js中添加数据初始化逻辑,更符合Context的封装原则:

// appState.js 修改部分
import React, { useReducer, useEffect } from 'react';
import AppContext from './appContext';
import AppReducer from './appReducer';
import getOpenCities from '../services/city/getOpenCities';

const AppState = (props) => {
  const initialState = {
    openCities: [],
  };

  const [state, dispatch] = useReducer(AppReducer, initialState);

  async function setAppState(payload) {
    dispatch({
      type: 'SET_APP_STATE',
      payload,
    });
  }

  // 在Context内部初始化数据
  useEffect(() => {
    const fetchOpenCities = async () => {
      const openCities = await getOpenCities();
      setAppState({ openCities: openCities.cities });
    };
    
    fetchOpenCities();
  }, []);

  return (
    <AppContext.Provider
      value={{
        openCities: state?.openCities,
        setAppState,
      }}
    >
      {props.children}
    </AppContext.Provider>
  );
};

export default AppState;

修改后,useContext(AppContext)就能正确获取Provider提供的setAppState,不会再出现undefined错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 06:45:37