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

React简易计数器应用报错:dispatch is not a function

React Context + useReducer 报错'dispatch is not a function'且counter初始值不显示的解决方法

问题根源

你在CounterApp组件的顶层直接调用useCounter()和useCounterDispatch(),但这两个Hook依赖的CounterProvider是在组件的return语句中才渲染的。React Context的作用范围仅限于Provider包裹的子组件,在Provider外层调用useContext会拿到Context的默认值(这里你设置的是null),所以会出现dispatch is not a function的错误,同时counter也无法获取到初始值0。

修复方案

将需要使用counter和dispatch的UI逻辑抽离成独立的子组件,让这个子组件被CounterProvider包裹,确保Hook在Context的作用域内调用。

修改后的代码

App.js

import { useEffect } from "react";
import { CounterProvider } from "./CounterContext";
import { useCounter, useCounterDispatch } from "./CounterContext";

// 抽离子组件,放在CounterProvider内部使用
function CounterControls() {
  const counter = useCounter();
  const dispatch = useCounterDispatch();

  useEffect(() => {
    console.log("counter: ", counter);
    console.log("dispatch: ", dispatch);
  }, [counter, dispatch]); // 添加依赖项,避免无限渲染

  return (
    <div>
      <button onClick={() => dispatch({ type: "increment" })}>
        increment
      </button>
      <button onClick={() => dispatch({ type: "decrement" })}>
        decrement
      </button>
      <button onClick={() => dispatch({ type: "reset" })}>
        reset
      </button>
      <h3>{counter}</h3>
    </div>
  );
}

export default function CounterApp() {
  return (
    <CounterProvider>
      <h2>Counter App</h2>
      <CounterControls />
    </CounterProvider>
  );
}

CounterContext.js(可选优化)

import { createContext, useContext, useReducer } from "react";

const CounterContext = createContext(null);
const CounterDispatch = createContext(null);

export function CounterProvider({ children }) {
  const [counter, dispatch] = useReducer(counterReducer, initialCounter);

  return (
    <CounterContext.Provider value={counter}>
      <CounterDispatch.Provider value={dispatch}>
        {children}
      </CounterDispatch.Provider>
    </CounterContext.Provider>
  );
}

export function useCounter() {
  return useContext(CounterContext);
}

export function useCounterDispatch() {
  return useContext(CounterDispatch);
}

// 优化reducer,去掉不必要的赋值操作
function counterReducer(counter, action) {
  switch (action.type) {
    case "increment":
      return counter + 1;
    case "decrement":
      return counter - 1;
    case "reset":
      return 0;
    default:
      throw Error("Unknown action: " + action.type);
  }
}

const initialCounter = 0;

额外说明

  • 抽离子组件后,CounterControls处于CounterProvider的作用域内,调用useCounter和useCounterDispatch时能正确获取到上下文提供的状态和dispatch函数。
  • 给useEffect添加依赖项是符合React Hook规则的做法,避免组件每次渲染都触发不必要的日志输出。
  • reducer中直接返回新状态值,比使用赋值语句更简洁规范,符合useReducer的使用习惯。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:02:53