Redux 是一个可预测的状态容器,它的设计非常精简,核心只有三个概念:Store、Action 和 Reducer,再配合中间件扩展异步能力。理解这四个概念,就能掌握 Redux 的本质。
Store:全局唯一的状态树
Store 是 Redux 的灵魂,它是整个应用唯一的数据仓库。在 Redux 中,所有的状态都存储在一棵 JavaScript 对象树里(即 state),而 Store 负责保管这棵树,并提供三个核心方法:
getState():获取当前状态。dispatch(action):派发一个 Action,触发状态更新。subscribe(listener):注册状态变化监听器(在 React 中通常由 react-redux 提供的useSelector自动处理)。
import { createStore } from 'redux';
const store = createStore(reducer);
console.log(store.getState()); // 当前状态
store.dispatch({ type: 'INCREMENT' });
console.log(store.getState()); // 更新后的状态
原则:一个应用只有一个 Store。如果状态逻辑复杂,可以通过 reducer 拆分(combineReducers)来组织代码,但顶层 Store 保持唯一。
Action:描述“发生了什么”
Action 是一个普通的 JavaScript 对象,它是改变 Store 的唯一途径。每个 Action 必须包含一个 type 字段(字符串常量),用于描述要执行的操作,可以携带额外数据(payload)。
// Action 示例
{ type: 'INCREMENT' }
{ type: 'ADD_TODO', payload: { text: '学习 Redux' } }
{ type: 'SET_USER', payload: { id: 1, name: 'Alice' } }
开发者不会直接修改 Store,而是通过 dispatch 发送一个 Action,表示“我想要做这件事”。Redux 强调意图驱动:你只告诉 Redux 发生了什么,具体怎么更新状态由 Reducer 决定。
在实际项目中,通常会使用 Action Creator 函数来生成 Action,提高复用性和类型安全:
const addTodo = (text) => ({ type: 'ADD_TODO', payload: { text } });
store.dispatch(addTodo('学习 Redux'));
Reducer:定义“状态如何变化”
Reducer 是一个纯函数,接收当前状态(state)和一个 Action,返回新状态:
(state, action) => newState
它负责根据 Action 的 type 来更新状态,必须遵守以下规则:
- 绝对不直接修改原 state(不可变更新):需要先复制,再修改副本,例如使用
{ ...state, key: newValue }或数组的map/filter/concat。 - 没有副作用:不能在里面执行请求、读写 DOM 等操作。
- 根据 action.type 返回不同的新状态,如果没有匹配到任何 Action,必须返回原 state(可以用 default 分支)。
一个典型的 Reducer:
const initialState = { count: 0 };
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
default:
return state;
}
}
当应用状态复杂时,我们会把根 Reducer 拆分成多个小型 Reducer,各自管理独立的状态片段,再用 combineReducers 合并:
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
counter: counterReducer,
user: userReducer,
todos: todosReducer,
});
中间件:扩展 dispatch 的能力
中间件(Middleware)是 Redux 的增强层,位于 dispatch Action 到到达 Reducer 之间。它可以拦截、修改 Action,或者处理异步逻辑(如 API 请求),然后将 Action 继续传递下去。
中间件的标准结构是一个三层嵌套函数:
const loggerMiddleware = store => next => action => {
console.log('dispatch:', action);
const result = next(action); // 传递给下一个中间件或 reducer
console.log('next state:', store.getState());
return result;
};
使用时通过 applyMiddleware 传入:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
const store = createStore(rootReducer, applyMiddleware(loggerMiddleware, thunk));
常见的中间件:
- redux-thunk:允许 Action Creator 返回一个函数(接收
dispatch和getState),用于处理异步操作,如请求数据后 dispatch 结果。 - redux-saga:使用生成器函数来管理复杂的异步流程和副作用,适合大型项目。
- redux-logger:在控制台打印每次状态的变更,方便调试。
中间件的工作流程:
- 组件
dispatch(action) - Action 进入中间件链,每个中间件可以决定是否继续传递、修改 Action,或触发新的 dispatch
- 最终 Action 到达所有 Reducer,计算出新状态
- 订阅该状态的组件自动更新
Redux 数据流一览
组件 dispatch(action) → 中间件链 → Reducer → 新 State → Store → 通知 UI 更新
整个流程单向、可预测,这也是 Redux 最大的价值所在。
现代 Redux:Redux Toolkit 简化
原生 Redux 写法存在样板代码多、手动处理不可变更新、异步逻辑分散等问题。Redux Toolkit(RTK) 提供了一组简化 API,成为官方推荐的标准写法:
configureStore:一键创建 Store,内置常用中间件(如 thunk)。createSlice:自动生成 Action Creators 和 Reducer,内部使用 Immer 库,可以“直接修改”状态(本质是代理拦截,生成不可变更新)。createAsyncThunk:优雅地处理异步请求,自动 dispatch pending/fulfilled/rejected 三种 Action。
import { createSlice, configureStore } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: state => { state.value += 1 },
decrement: state => { state.value -= 1 },
},
});
const store = configureStore({ reducer: counterSlice.reducer });
虽然 API 变得更友好,但核心概念(Store、Action、Reducer、中间件)完全保留。理解底层原理,可以帮助你更好地调试和优化 Redux 应用。