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

仅用useReducer实现共享状态是否可行?求代码问题排查建议

你的useReducer共享状态实现问题及修复方案

核心问题

你当前的代码无法实现跨组件状态同步,点击AnyComponent的按钮后,只有该组件的counter会更新,OtherComponent的counter永远停留在初始值0。

问题根源

你把Store写成了自定义Hook,但React的自定义Hook规则是:每次调用自定义Hook,都会创建独立的状态和副作用实例。也就是说,AnyComponent和OtherComponent各自调用Store()时,都会初始化一个全新的useReducer状态,两者完全隔离,根本不是同一个“单Store”。

正确的实现方式:结合Context实现单Store共享

要实现类似Redux的单Store模式,需要把useReducer的状态和dispatch通过React Context传递给所有需要的组件,确保所有组件共享同一个状态实例。

修改后的Store.js

import { useReducer, createContext, useContext } from "react";
import { ACTION_TYPES } from "./storeActionTypes";

export const INITIAL_STATE = {
  counter: 0,
};

export const storeReducer = (state, action) => {
  switch (action.type) {
    case ACTION_TYPES.INCREASE_COUNTER_BY_1:
      return {
        ...state,
        counter: state.counter + 1,
      };
    default:
      return state;
  }
};

// 创建状态Context
const StoreContext = createContext();

// 提供状态的Provider组件,需包裹整个需要共享状态的组件树
export const StoreProvider = ({ children }) => {
  const [state, dispatch] = useReducer(storeReducer, INITIAL_STATE);
  return (
    <StoreContext.Provider value={{ state, dispatch }}>
      {children}
    </StoreContext.Provider>
  );
};

// 自定义Hook,简化组件获取状态的逻辑
export const useStore = () => {
  const context = useContext(StoreContext);
  // 防止组件在Provider外部调用该Hook导致错误
  if (!context) {
    throw new Error("useStore must be used within a StoreProvider");
  }
  return context;
};

修改后的AnyComponent.js

import React from "react";
import { useStore } from "../store/Store";
import { ACTION_TYPES } from "../store/storeActionTypes"; // 引入常量避免硬编码

const AnyComponent = () => {
  const { state: store, dispatch } = useStore();

  const handleIncreaseByOne = (e) => {
    e.preventDefault();
    dispatch({ type: ACTION_TYPES.INCREASE_COUNTER_BY_1 });
  };

  return (
    <div>
      <button onClick={handleIncreaseByOne}>Submit</button>
      <span>counter from AnyComponent.js:{store.counter}</span>
    </div>
  );
};

export default AnyComponent;

修改后的OtherComponent.js

(注意原代码存在语法错误:组件名不能带.js后缀,已修正)

import React from "react";
import { useStore } from "../store/Store";

const OtherComponent = () => {
  const { state: store } = useStore();

  return (
    <div>
      <span>counter from OtherComponent.js:{store.counter}</span>
    </div>
  );
};

export default OtherComponent;

根组件配置

在你的根组件(如App.js)中,用StoreProvider包裹所有需要共享状态的组件:

import { StoreProvider } from "./store/Store";
import AnyComponent from "./AnyComponent";
import OtherComponent from "./OtherComponent";

function App() {
  return (
    <StoreProvider>
      <AnyComponent />
      <OtherComponent />
    </StoreProvider>
  );
}

export default App;

额外建议

  • 始终使用ACTION_TYPES常量而非硬编码字符串,避免拼写错误,同时便于统一管理action类型
  • 若后续状态逻辑复杂,可以拆分reducer函数,或者实现一个简易的useSelectorHook(基于useStore和useMemo)来避免不必要的组件重渲染
  • 可以给Context的默认值传入空对象或null,但在useStore中加入错误判断能提前发现使用错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:26:05