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

使用自定义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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 19:54:24