90%的中小型React应用用useReducer+useContext足够;Redux Toolkit才值得在需时间旅行、服务端同步、复杂中间件或跨组件高频共享状态时评估;派生状态不应进store,而该用useMemo或createSelector计算。

JavaScript 中不需要“从单向数据流讲到 Redux 模式”来实现状态管理——真正需要的,是根据场景选对工具,避免过早抽象。
什么时候该自己写 useState + useReducer,而不是引入 Redux?
90% 的中小型 React 应用,useReducer 配合 useContext 就够用了。Redux 的核心价值不在“状态可预测”,而在于:需要时间旅行调试、服务端状态同步、大量中间件(如 redux-thunk 或 redux-saga)、跨多个不相关组件共享且频繁更新的状态。
- 表单联动、模态框开关、主题切换 → 用
useState或useReducer - 购物车 + 用户登录态 + 实时通知三者互相影响 → 可考虑
useReducer+ 自定义 Hook 封装 - 需要回放用户操作、离线优先、与后端状态强一致 → 才值得评估 Redux Toolkit(不是原生 Redux)
useReducer 的常见误用:把所有 state 都塞进一个 reducer
这不是单向数据流的问题,是职责混淆。一个 reducer 应该只负责一类逻辑闭环的状态变更,比如 cartReducer 管购物车,authReducer 管登录态,而不是全塞进 appReducer。
错误示例:
立即学习“Java免费学习笔记(深入)”;
const appReducer = (state, action) => {
switch (action.type) {
case 'ADD_TO_CART':
return { ...state, cart: [...state.cart, action.item] };
case 'LOGIN_SUCCESS':
return { ...state, user: action.user, isLoggedIn: true };
case 'NOTIFY':
return { ...state, notifications: [...state.notifications, action.msg] };
default:
return state;
}
};问题:任意 action 都可能意外修改其他字段;无法单独测试;reducer 越来越大。
推荐做法:拆分 + 组合
const cartReducer = (state, action) => { /* ... */ };
const authReducer = (state, action) => { /* ... */ };
const rootReducer = (state, action) => ({
cart: cartReducer(state.cart, action),
auth: authReducer(state.auth, action),
});
Redux Toolkit 的 createSlice 不是语法糖,它解决了原生 Redux 的三个硬伤
很多人以为 createSlice 只是自动写 action.type 字符串,其实它关键在:immer 支持可变写法、自动合并 reducers 和 extraReducers、内置 createAsyncThunk 处理副作用。
- 不用再手写
switch和return {...state}—— 直接state.items.push(item) - 异步请求不再需要三层 action(
PENDING/FULFILLED/REJECTED)手动 dispatch -
configureStore默认开启serializableCheck和immutableCheck,提前暴露不可序列化值(如函数、Date)
典型漏掉的配置:
import { configureStore } from '@reduxjs/toolkit';
import { setupListeners } from '@reduxjs/toolkit/query';
const store = configureStore({
reducer: { / ... / },
middleware: (getDefault) =>
getDefault().concat(yourCustomMiddleware), // 忘加这行,RTK Query 不生效
});
setupListeners(store.dispatch); // 忘加这行,refetch 等行为不触发
状态管理最容易被忽略的复杂点:派生状态不该进 store
比如「购物车总价」、「已读消息数」、「筛选后的商品列表」——这些是计算结果,不是源状态。放进 Redux store 会导致:重复计算、缓存失效、与原始数据不同步。
正确方式:
- React 中用
useMemo或createSelector(Reselect)缓存派生值 - Redux Toolkit 中用
createEntityAdapter+getSelectors自动处理排序/过滤 - 永远只在 store 里存
cartItems: [{id, qty}],不要存totalPrice: 129.99
一旦发现某个字段总要和另一个字段一起更新,或者每次都要靠 useEffect 同步它,那它大概率不该是独立 state。










