Can't make Context API work on React application, Uncaught TypeError: react__WEBPACK_IMPORTED_MODULE_0__.useContext(...) is not iterable

Can't make Context API work on React application, Uncaught TypeError: react__WEBPACK_IMPORTED_MODULE_0__.useContext(...) is not iterable

我正在尝试让 ContextAPI 在我的应用程序上运行,webpack 编译一切,但在浏览器上我得到

Uncaught TypeError: react__WEBPACK_IMPORTED_MODULE_0__.useContext(...) is not iterable

这是我第一次尝试在项目中使用 ContextAPI。

在 index.js

 ReactDOM.render(
    <React.StrictMode>
        <Router>
            <RoutesTree />
        </Router>
    </React.StrictMode>,
    document.getElementById('app')
);

在 RoutesTree.js

const DEFAULT_STATE = {
    state: {
        users: [],
        teams: []
    },
    setState: () => {}
};

export const AppContext = createContext(DEFAULT_STATE);

const RoutesTree = () => {
    const [state, setState] = useState(DEFAULT_STATE.state);
    const value = useMemo(
      () => ((state, setState)),
      [state]
    );
  
    console.log('state', state);

    return (
        <AppContext.Provider value={value}>
            <Routes>
                <Route path='/' element={<App />} />
                <Route path='/teams/:id' element={<Team />} />
            </Routes>
        </AppContext.Provider>
    )
}

export default RoutesTree;

于 App.js(进行中)

const App = () => {

  return (
      <>
          <Home />
      </>
  );
}

在 Home.js

const Home = () => {
    const [state, setState] = useContext(AppContext);

    useEffect(() => {
        const getTeams = async () => {
            const response = await axios.get(teamsApiUrl);
            
            setState((prevState) => ({
                teams: response.data,
                users: prevState.users
            }));
        }

        getTeams();
    }, [])

完全错误:

Uncaught TypeError: react__WEBPACK_IMPORTED_MODULE_0__.useContext(...) is not iterable
    Home webpack://ecore-project/./src/components/Home/Home.js?:32
    React 16
    <anonymous> webpack://ecore-project/./src/index.js?:15
    js http://localhost:8080/main.js:500
    __webpack_require__ http://localhost:8080/main.js:1313
    <anonymous> http://localhost:8080/main.js:2403
    <anonymous> http://localhost:8080/main.js:2405 main.js line 434 > eval:32:78 The above error occurred in the <Home> component:

Home@webpack://ecore-project/./src/components/Home/Home.js?:32:78 App Routes@webpack://ecore-project/./node_modules/react-router/index.js?:922:7 RoutesTree@webpack://ecore-project/./src/components/RoutesTree/RoutesTree.js?:25:76 Router@webpack://ecore-project/./node_modules/react-router/index.js?:860:7 BrowserRouter@webpack://ecore-project/./node_modules/react-router-dom/index.js?:122:7

Consider adding an error boundary to your tree to customize error handling behavior. Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries. react-dom.development.js:18572:15
    React 16
    <anonymous> webpack://ecore-project/./src/index.js?:15
    js http://localhost:8080/main.js:500
    __webpack_require__ http://localhost:8080/main.js:1313
    <anonymous> http://localhost:8080/main.js:2403
    <anonymous> http://localhost:8080/main.js:2405 Uncaught TypeError: react__WEBPACK_IMPORTED_MODULE_0__.useContext(...) is not iterable
    Home webpack://ecore-project/./src/components/Home/Home.js?:32
    React 13
    <anonymous> webpack://ecore-project/./src/index.js?:15
    js http://localhost:8080/main.js:500
    __webpack_require__ http://localhost:8080/main.js:1313
    <anonymous> http://localhost:8080/main.js:2403
    <anonymous> http://localhost:8080/main.js:2405

webpack 编译器:

<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:8080/
<i> [webpack-dev-server] On Your Network (IPv4): http://192.168.0.100:8080/
<i> [webpack-dev-server] Content not from webpack is served from 'C:\Users\Alvaro\git\ecore-project\public' directory
asset main.js 1.84 MiB [emitted] (name: main)
asset ./index.html 230 bytes [emitted]
runtime modules 27.5 KiB 14 modules
modules by path ./node_modules/ 1.61 MiB 90 modules
asset modules 4.4 KiB
  data:image/svg+xml,%3csvg xmlns=%27.. 281 bytes [built] [code generated]
  data:image/svg+xml,%3csvg xmlns=%27.. 279 bytes [built] [code generated]
  data:image/svg+xml,%3csvg xmlns=%27.. 161 bytes [built] [code generated]
  data:image/svg+xml,%3csvg xmlns=%27.. 271 bytes [built] [code generated]
  + 12 modules
modules by path ./src/ 12.8 KiB
  modules by path ./src/components/ 7.9 KiB 6 modules
  modules by path ./src/*.js 683 bytes 2 modules
  modules by path ./src/*.css 2.66 KiB 2 modules
  ./src/utils/usePagination.js 1.59 KiB [built] [code generated]
webpack 5.72.1 compiled successfully in 1741 ms

问题

问题在于您尝试计算记忆上下文值的方式。

const value = useMemo(
  () => ((state, setState)), // <-- not an iterable value!
  [state]
);

这并不完全是你想的那样,当 Home 组件尝试使用数组解构赋值访问状态和状态更新函数时,代码会崩溃。

const [state, setState] = useContext(AppContext); // <-- tries to access array

() => ((state, setState)) 实际上是返回 Comma Operator 表达式的结果。 setState 函数是作为记忆值返回的。

使这个问题更加复杂的是上下文值被声明为对象而不是数组。

const DEFAULT_STATE = {
  state: {
    users: [],
    teams: []
  },
  setState: () => {}
};

export const AppContext = createContext(DEFAULT_STATE);

解决方案

我确定您是想记忆一个对象。

const value = useMemo(
  () => ({ state, setState }),
  [state]
);

现在消费者需要正确解构对象。它是一个对象,而不是数组。

const { state, setState } = useContext(AppContext);