I'm trying to make ContextAPI work on my application, webpack compiles everything, but on the browser I get
Uncaught TypeError: react__WEBPACK_IMPORTED_MODULE_0__.useContext(...) is not iterable
This is the first I'm trying to use ContextAPI in a project.
On index.js
ReactDOM.render(
<React.StrictMode>
<Router>
<RoutesTree />
</Router>
</React.StrictMode>,
document.getElementById('app')
);
on 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;
on App.js (work in progress)
const App = () => {
return (
<>
<Home />
</>
);
}
on 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();
}, [])
Complete error:
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 compiler:
<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,
CodePudding user response:
Issue
The issue is how you are trying to compute a memoized context value.
const value = useMemo(
() => ((state, setState)), // <-- not an iterable value!
[state]
);
It's not exactly what you think it is, and the code blows up in the Home
component when it tries to use array destructuring assignment to access the state and state updater function.
const [state, setState] = useContext(AppContext); // <-- tries to access array
() => ((state, setState))
is actually returning the result of a Comma Operator expression. The setState
function is what is returned as a memoized value.
Compounding this issue is that the context value was declared to be an object and not an array.
const DEFAULT_STATE = {
state: {
users: [],
teams: []
},
setState: () => {}
};
export const AppContext = createContext(DEFAULT_STATE);
Solution
I am certain you meant to memoize an object instead.
const value = useMemo(
() => ({ state, setState }),
[state]
);
Now the consumer needs to destructure the object correctly. It's an object, not an array.
const { state, setState } = useContext(AppContext);