使用自定义Hook处理Context中TODOS时触发TypeError: useContext(...) is undefined错误
错误原因
你在TodoProvider组件内部调用了useTodos,而useTodos里通过useContext(TodoContext)获取上下文,但此时TodoContext.Provider还未完成渲染,useContext返回undefined,解构dispatchTodos自然触发了类型错误。
修复方案
方案1:让useTodos接收dispatchTodos作为参数
修改useTodos.js,不再通过useContext获取dispatchTodos,改为从外部传入:
import { types } from '../types/types'; export const useTodos = (dispatchTodos) => { const handleNewTodo = todo => { const action = { type: types.add, payload: todo, }; dispatchTodos(action); }; const handleToggleTodo = id => { dispatchTodos({ type: types.toggle, payload: id, }); }; return { handleNewTodo, handleToggleTodo }; };
然后在TodoProvider.jsx中调用useTodos时传入dispatchTodos:
import { useReducer } from 'react'; import { useTodos } from '../hooks/useTodos'; import { TodoContext, todoReducer } from './'; export const TodoProvider = ({ children }) => { const init = () => { return []; }; const [todos, dispatchTodos] = useReducer(todoReducer, {}, init); // 传入dispatchTodos const { handleNewTodo, handleToggleTodo } = useTodos(dispatchTodos); return ( <TodoContext.Provider value={{ todos, dispatchTodos, handleNewTodo, handleToggleTodo }} > {children} </TodoContext.Provider> ); };
方案2:将useTodos的调用移到Provider的子组件中
把useTodos的调用放在需要使用这些处理函数的子组件里(比如TodoList、TodoForm),此时这些组件已被TodoContext.Provider包裹,useContext能正确获取上下文值。
示例:在TodoForm组件中使用useTodos
import { useTodos } from '../hooks/useTodos'; export const TodoForm = () => { const { handleNewTodo } = useTodos(); const handleSubmit = (e) => { e.preventDefault(); handleNewTodo({ id: Date.now(), text: '新待办', done: false }); }; return ( <form onSubmit={handleSubmit}> {/* 表单内容 */} <button type="submit">添加待办</button> </form> ); };
同时修改TodoProvider,不再在内部调用useTodos,直接把dispatchTodos放入Context的value中:
import { useReducer } from 'react'; import { TodoContext, todoReducer } from './'; export const TodoProvider = ({ children }) => { const init = () => { return []; }; const [todos, dispatchTodos] = useReducer(todoReducer, {}, init); return ( <TodoContext.Provider value={{ todos, dispatchTodos }} > {children} </TodoContext.Provider> ); };
此时useTodos的原代码无需修改,就能在子组件中正常工作。
内容的提问来源于stack exchange,提问作者LugpDev2022
相关产品推荐
相关产品推荐

