Article

状态管理 Redux

更新于:2026-07-11

第一章:Redux 基础概念

1.1 什么是 Redux

概念名称说明注意事项
Redux状态管理库,集中管理 JavaScript 应用的状态,适用于大型、状态频繁变化的应用。例如在单页应用中管理用户登录状态、购物车数据等不是每个项目都需要 Redux,小型应用可直接使用组件内状态

1.2 Redux 核心原则

概念名称说明注意事项
单一数据源整个应用的 state 被存储在单一的 store 中,便于调试、持久化和状态追踪,所有组件共享一个 store 对象避免创建多个 store,保持状态集中
状态只读不能直接修改 state,只能通过 dispatch action 来触发变更,保证状态变化可预测。例如不能写 state.count++,必须 dispatch({ type: 'INCREMENT' })直接修改 state 不会触发视图更新,且违反 Redux 原则
使用纯函数更新使用 reducer 函数根据旧 state 和 action 计算出新 state,确保状态变化可追踪、可测试,即 reducer(state, action) => newStatereducer 必须是纯函数,不能有副作用(如 API 调用、修改参数)

1.3 Store、State、Action、Reducer 概念解析

概念名称说明注意事项
Store通过 createStore(reducer) 创建,存储整个应用的状态树,提供 getStatedispatchsubscribe 接口。例如 const store = createStore(counterReducer)应用中只应有一个 store
Statestore.getState() 的返回值,表示应用在某一时刻的状态快照。例如 { count: 0, user: null }状态是只读的,不能直接修改
Action普通 JavaScript 对象,必须有 type 字段,描述状态变化的意图(“做什么”)。例如 { type: 'INCREMENT', payload: 1 }action 必须是对象,type 字段不可省略,建议使用常量定义 type
Reducer(state, action) => newState,根据 action 的 type 决定如何更新 state。例如 function counterReducer(state = 0, action) { ... }必须是纯函数;不能修改 state,应返回新对象;不能有异步操作

第二章:Store 的创建与管理

2.1 创建 Store(createStore)

方法语法用途代码示例注意事项
createStorecreateStore(reducer, [preloadedState], [enhancer])创建 Redux store 来存放应用的全局状态import { createStore } from 'redux';
const store = createStore(counterReducer);
第二个参数为可选的初始状态,第三个参数用于添加中间件或增强器;reducer 必须是函数

2.2 获取状态(getState)

方法语法用途代码示例注意事项
getStatestore.getState()获取当前 store 中保存的 state 树const currentState = store.getState();
console.log(currentState);
返回的是当前状态的引用,但状态不可直接修改;常用于调试或同步读取状态

2.3 监听状态变化(subscribe)

方法语法用途代码示例注意事项
subscribestore.subscribe(listener)注册一个监听函数,当 state 更新时自动执行const unsubscribe = store.subscribe(() => {
console.log('状态更新:', store.getState());
});
监听器会在每次 dispatch action 后被调用;不保证每次状态变化都不同,需手动比较前后状态;适用于非 React 环境的视图更新

2.4 销毁监听器

方法语法用途代码示例注意事项
unsubscribesubscribe 返回的函数调用移除状态变化的监听器,防止内存泄漏const unsubscribe = store.subscribe(() => {
console.log('监听中...');
});
// 停止监听
unsubscribe();
一旦调用,该监听器不再执行;在组件卸载或不需要监听时务必调用,避免性能问题

第三章:Action 与 Action Creator

3.1 定义 Action 对象

方法语法用途代码示例注意事项
Action 对象{ type: string, ...payload }描述状态变更的意图,是 store 的唯一数据来源{ type: 'ADD_TODO', payload: '学习 Redux' }必须包含 type 字段;type 通常为常量字符串;建议使用 payload 字段传递数据

3.2 使用 Action Creator 生成 Action

方法语法用途代码示例注意事项
Action Creator函数,返回一个 action 对象封装 action 的创建逻辑,便于复用和测试function addTodo(text) {
return {
type: 'ADD_TODO',
payload: text
};
}
// 使用:
store.dispatch(addTodo('写代码'));
函数必须返回一个合法的 action 对象;本身不触发状态变更,需配合 dispatch 使用
常量定义 typeconst ADD_TODO = 'ADD_TODO'集中管理 action type,避免拼写错误const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
function increment() {
return { type: INCREMENT };
}
推荐将所有 type 定义为常量并集中存放,提升可维护性

3.3 异步 Action 简介

方法语法用途代码示例注意事项
异步 Action(概念)返回函数或使用中间件处理的 action处理异步操作,如 API 请求、定时任务// 使用 redux-thunk:
function fetchUser() {
return (dispatch) => {
dispatch({ type: 'FETCH_USER_START' });
api.getUser().then(user => {
dispatch({ type: 'FETCH_USER_SUCCESS', payload: user });
});
};
}
普通 reducer 无法处理异步逻辑;必须引入中间件(如 redux-thunk)才能支持函数形式的 action
中间件支持异步applyMiddleware(thunk)扩展 dispatch 功能,使其能处理函数或 Promiseconst store = createStore(
reducer,
applyMiddleware(thunk)
);
createStore 时需应用中间件,否则 dispatch 函数类型的 action 会报错

第四章:Reducer 函数设计

4.1 Reducer 基本结构

方法语法用途代码示例注意事项
Reducer 函数(state, action) => newState根据当前 state 和接收到的 action 计算并返回新的 statefunction counterReducer(state = 0, action) {
switch (action.type) {
default:
return state;
}
}
必须指定初始状态(如 state = 0);必须有默认返回,防止未知 action 导致 state 为 undefined

4.2 处理不同 Action 类型

方法语法用途代码示例注意事项
switch 语句处理 action.typeswitch(action.type) { case 'TYPE': ... }根据不同的 action 类型执行不同的状态更新逻辑function counterReducer(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
每个 case 应返回新状态;必须包含 default 分支返回原 state;避免在 case 中使用 break,以免遗漏 return 导致错误

4.3 使用 combineReducers 合并多个 Reducer

方法语法用途代码示例注意事项
combineReducerscombineReducers({ reducer1, reducer2 })将多个子 reducer 合并为一个根 reducer,用于管理复杂状态树function todos(state = [], action) { ... }
function filters(state = 'all', action) { ... }
const rootReducer = combineReducers({
todos,
filters
});
const store = createStore(rootReducer);
参数为一个对象,键名对应 state 的字段名;合并后的 state 结构由对象键决定;每个子 reducer 只管理自己的局部 state
嵌套状态结构state.todos / state.filters访问 combineReducers 生成的嵌套 stateconst todoList = store.getState().todos;
const filter = store.getState().filters;
使用 combineReducers 后,state 变为分层结构,需通过属性访问对应模块

4.4 Reducer 编写注意事项

方法语法用途代码示例注意事项
纯函数要求不修改参数、无副作用、相同输入始终返回相同输出确保状态更新可预测、可调试// 正确:返回新数组
return [...state, newItem];
// 错误:修改原数组
state.push(newItem); return state;
避免使用 pushpopsplice 等会修改原数组的方法
状态不可变性(Immutability)始终返回新对象/数组,而非修改原对象防止意外状态变更,支持时间旅行调试// 数组添加元素
return [...state, action.payload];
// 对象更新属性
return { ...state, name: action.payload };
对象和数组都应使用扩展运算符或库(如 immer)创建副本,禁止直接赋值修改
默认返回原 statereturn state;处理未知 action 时保持状态不变default:
return state;
必须包含 default 分支,否则未知 action 会导致 state 变为 undefined

第五章:中间件与异步操作

5.1 中间件概念(Middleware)

方法语法用途代码示例注意事项
Middleware(中间件)({ getState, dispatch }) => next => action扩展 Redux 的功能,拦截或处理 dispatch 的 actionconst logger = store => next => action => {
console.log('dispatching:', action);
const result = next(action);
console.log('next state:', store.getState());
return result;
}
中间件位于 action 发出之后、到达 reducer 之前;可用于日志、异步处理、路由等;函数结构为三层箭头函数

5.2 应用中间件(applyMiddleware)

方法语法用途代码示例注意事项
applyMiddlewareapplyMiddleware(middleware1, middleware2)将多个中间件应用到 createStore 中,增强 store 功能import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import logger from './logger';
const store = createStore(
reducer,
applyMiddleware(thunk, logger)
);
必须作为 createStore 的第二个参数或通过 enhancer 传入;中间件执行顺序从左到右;是使用异步 action 的前提

5.3 使用 redux-thunk 实现异步 Action

方法语法用途代码示例注意事项
redux-thunk函数形式的 action creator允许 action creator 返回一个函数,接收 dispatch 和 getStatefunction fetchPosts() {
return (dispatch, getState) => {
dispatch({ type: 'FETCH_POSTS_START' });
api.getPosts().then(posts => {
dispatch({
type: 'FETCH_POSTS_SUCCESS',
payload: posts
});
});
};
}
// 使用:
store.dispatch(fetchPosts());
必须先通过 applyMiddleware(thunk) 启用;返回的函数可访问 dispatch 和 getState,适合处理异步逻辑;不能在普通 reducer 中直接调用 API
异步三态处理REQUEST / SUCCESS / FAILURE管理异步操作的加载、成功、失败状态{ type: 'FETCH_USER_REQUEST' }
{ type: 'FETCH_USER_SUCCESS', payload: user }
{ type: 'FETCH_USER_FAILURE', error: 'Network error' }
建议为每个异步流程定义三种 action 类型,便于 UI 显示加载状态和错误提示

5.4 常见中间件介绍

方法语法用途代码示例注意事项
redux-loggerimport { createLogger } from 'redux-logger';
const logger = createLogger();
applyMiddleware(logger)
在控制台打印 action 和状态变化,用于调试// 控制台输出:
action FETCH_POSTS_START @ 10:20:30
prev state: { posts: [] }
action: { type: 'FETCH_POSTS_START' }
next state: { loading: true }
建议仅在开发环境使用,生产环境应移除以避免性能损耗
redux-saga使用 generator 函数管理副作用处理复杂的异步流程、任务调度、并发控制import { takeEvery, call, put } from 'redux-saga/effects';
function* fetchUserSaga() {
try {
const user = yield call(api.fetchUser);
yield put({ type: 'FETCH_SUCCESS', payload: user });
} catch (e) {
yield put({ type: 'FETCH_FAIL' });
}
}
学习成本较高,适用于复杂异步场景;比 thunk 更强大但更重;需单独启动 saga 任务(sagaMiddleware.run

注意:普通 reducer 无法处理异步逻辑,必须先通过 applyMiddleware 启用相应中间件(如 redux-thunk 或 redux-saga),否则 dispatch 函数类型的 action 会导致报错。

第六章:Redux 与 React 集成

6.1 使用 react-redux 提供 Provider

方法/组件语法用途代码示例注意事项
Provider<Provider store={store}>...</Provider>将 Redux store 注入 React 组件树,使所有子组件可通过 useSelector/useDispatch 访问 storeimport { Provider } from 'react-redux';
import store from './store';
function App() {
return (
<Provider store={store}>
<CounterDisplay />
</Provider>
);
}
必须在根组件(如 App)外层包裹;store 只需传入一次;Provider 不渲染 DOM 元素,仅传递上下文

6.2 使用 useSelector 读取状态

钩子名称语法用途代码示例注意事项
useSelectorconst value = useSelector(selectorFn)从 Redux store 中提取所需状态import { useSelector } from 'react-redux';
function CounterDisplay() {
const count = useSelector(state => state.count);
return <div>{count}</div>;
}
selector 函数接收整个 state 并返回需要的部分;组件会在 selector 返回值变化时重新渲染;避免在 selector 中返回新对象(如 state.todos.map(...) 应 memoize)

6.3 使用 useDispatch 派发 Action

钩子名称语法用途代码示例注意事项
useDispatchconst dispatch = useDispatch()获取 dispatch 函数,用于派发 actionimport { useDispatch } from 'react-redux';
import { increment } from './actions';
function CounterButton() {
const dispatch = useDispatch();
return (
<button onClick={() => dispatch(increment())}>+1</button>
);
}
useDispatch 返回的是 store.dispatch 的引用;应在事件处理函数中调用 dispatch;避免在渲染过程中直接 dispatch(除非在 useEffect 内)

6.4 使用 connect 连接组件(旧版 API)

方法名称语法用途代码示例注意事项
connectconnect(mapStateToProps, mapDispatchToProps)(Component)高阶函数,将 React 组件连接到 Redux store(类组件时代标准)function Counter({ count, onIncrement }) {
return (
<div>
<span>{count}</span>
<button onClick={onIncrement}>+1</button>
</div>
);
}
const mapStateToProps = state => ({
count: state.count
});
const mapDispatchToProps = {
onIncrement: () => ({ type: 'INCREMENT' })
};
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
mapStateToProps 提供 state 映射,mapDispatchToProps 提供 action 派发方法;已逐渐被 hooks(useSelector/useDispatch)取代;适用于类组件或需深度优化的场景
mapStateToProps(state) => object将 store 中的状态映射为组件的 propsconst mapStateToProps = state => ({
user: state.user,
loading: state.loading
});
必须是纯函数;返回对象将合并到组件 props;若不监听 state,可设为 null
mapDispatchToPropsobject(dispatch) => object将 action creator 绑定到 props,或返回 dispatch 调用// 方式一:对象形式(自动绑定)
const mapDispatchToProps = {
increment,
decrement
}
// 方式二:函数形式
const mapDispatchToProps = dispatch => ({
onClick: () => dispatch({ type: 'CLICK' })
});
对象形式会自动调用 bindActionCreator;函数形式更灵活,适合封装逻辑;不传则默认注入 dispatch

第七章:项目结构与最佳实践

7.1 典型文件组织方式

组织方式结构说明用途代码示例(目录结构)注意事项
按类型组织(by type)将相同类型的文件归类到同一目录适合小型项目或初学者快速上手src/
actions/
counter.js
user.js
reducers/
counter.js
user.js
index.js
store.js
随着功能增多,跨文件跳转频繁,维护成本上升;功能逻辑分散
按功能组织(by feature)每个功能模块包含自己的 action、reducer、state提高模块内聚性,便于团队协作和代码复用src/
features/
counter/
counterSlice.js
counterActions.js
user/
userSlice.js
userService.js
store.js
推荐现代 Redux 项目使用;功能独立,易于拆分和测试

7.2 Ducks 模式简介

概念名称语法/结构用途代码示例注意事项
Ducks 模式将 action type、action creator 和 reducer 定义在同一个文件中减少文件拆分,提升模块化程度,遵循”一个功能一个文件”原则// features/counter/counter.js
const INCREMENT = 'counter/INCREMENT';
const DECREMENT = 'counter/DECREMENT';
export function increment() {
return { type: INCREMENT };
}
export function decrement() {
return { type: DECREMENT };
}
const initialState = 0;
export default function counterReducer(state = initialState, action) {
switch (action.type) {
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
default:
return state;
}
}
action type 应带模块前缀(如 'counter/INCREMENT')避免冲突;最终仍可通过 combineReducers 合并;适合中等复杂度项目

7.3 状态设计原则

原则名称说明用途代码示例注意事项
状态扁平化尽量使用一维或二维结构,避免深层嵌套提高查找效率,简化更新逻辑{
users: {
byId: { 1: { name: 'Alice' } },
allIds: [1]
}
}
推荐使用”ID 列表 + 查找表”结构管理集合数据
单一数据源每个数据只在 state 中存在一份避免数据冗余和不一致用户信息只在 user 模块中定义,不重复出现在 order 模块所有组件共享同一份状态,通过 selector 提取
可预测性状态变化应由 action 明确描述便于调试和回放dispatch({ type: 'SET_USER', payload: user })避免在多个 reducer 中响应同一 action 修改不同状态,除非有明确依赖
不可变更新始终返回新对象,不修改原 state保证 Redux 时间旅行和性能优化有效return { ...state, name: 'Bob' };
return state.filter(id => id !== 1);
使用扩展运算符、filter、map 等函数式方法;避免直接 push、splice、赋值修改

7.4 调试工具(Redux DevTools)

工具名称语法/使用方式用途代码示例注意事项
Redux DevTools Extension浏览器插件(Chrome/Firefox)实时查看 action、state 变化,支持时间旅行调试安装插件后自动生效必须在 createStore 时启用增强器才能使用完整功能
DevTools 增强器window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()在代码中启用 DevTools 功能const store = createStore(
rootReducer,
applyMiddleware(thunk),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
生产环境应移除或通过条件判断禁用:process.env.NODE_ENV !== 'production'
configureStore(RTK)import { configureStore } from '@reduxjs/toolkit';Redux Toolkit 默认集成 DevTools,无需手动添加增强器const store = configureStore({ reducer })推荐新项目使用 RTK,开箱即用调试支持

第八章:现代 Redux:Redux Toolkit 入门

8.1 为什么需要 Redux Toolkit

概念名称说明用途代码示例注意事项
Redux Toolkit (RTK)官方推荐的 Redux 逻辑编写方式解决传统 Redux 样板代码过多、配置复杂的问题,提供高效、简洁的 APIimport { createSlice, configureStore } from '@reduxjs/toolkit';是 Redux 官方团队维护的现代工具集;新项目应优先使用 RTK 而非原始 Redux 写法;内置了不可变更新、DevTools 支持等

8.2 createSlice 简化 reducer 和 action 创建

方法名称语法用途代码示例注意事项
createSlicecreateSlice({ name, initialState, reducers })自动生成 action creator 和 action type,并创建对应的 reducerimport { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: 0,
reducers: {
incremented: state => state + 1,
decremented: state => state - 1,
added: (state, action) => state + action.payload
}
});
export const { incremented, decremented, added } = counterSlice.actions;
export default counterSlice.reducer;
reducer 中可”直接修改”state(借助 immer 实现不可变更新);action type 自动生成为 ${name}/${reducerName}(如 'counter/incremented');自动创建 action creator
自动生成 action type${name}/${reducerKey}命名规范化,避免手动定义字符串常量incremented().type // 'counter/incremented'无需手动定义 ADD_TODO 等常量,减少出错可能
”直接修改” statestate++在 reducer 中看似修改原 state,实则生成新对象case: incremented:
state.value++ // 合法
仅在 createSlice 或 createReducer 中支持;依赖 immer 库,不可用于普通 reducer

8.3 configureStore 简化 store 配置

方法名称语法用途代码示例注意事项
configureStoreconfigureStore({ reducer, middleware?, devTools?, preloadedState })简化 store 创建过程,自动合并 reducer、应用默认中间件并启用 DevToolsimport { configureStore } from '@reduxjs/toolkit';
import counterReducer from './features/counter/counterSlice';
const store = configureStore({
reducer: {
counter: counterReducer
}
});
export default store;
自动调用 combineReducers;默认包含 redux-thunk 和 DevTools 增强器;开发环境自动启用日志和检查;比 createStore 更安全、简洁
合并多个 slice reducer{ sliceName: slice.reducer }构建根 reducer 对象const store = configureStore({
reducer: {
counter: counterSlice.reducer,
user: userSlice.reducer
}
});
键名决定最终 state 的结构(如 state.counter

8.4 异步逻辑处理:createAsyncThunk

方法名称语法用途代码示例注意事项
createAsyncThunkcreateAsyncThunk(typePrefix, asyncCallback)创建处理异步逻辑的 thunk action,自动 dispatch pending/fulfilled/rejected actionimport { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
export const fetchUser = createAsyncThunk(
'user/fetchUser',
async (userId, { rejectWithValue }) => {
const response = await api.getUser(userId);
return response.data;
}
);
const userSlice = createSlice({
name: 'user',
initialState: { data: null, loading: false },
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => {
state.loading = true;
})
.addCase(fetchUser.fulfilled, (state, action) => {
state.data = action.payload;
state.loading = false;
})
.addCase(fetchUser.rejected, (state) => {
state.loading = false;
});
}
});
typePrefix 用于生成 action type(如 user/fetchUser/pending);asyncCallback 接收参数和 thunk API;自动处理异步三态
extraReducersbuilder => builder.addCase(...)在 createSlice 中处理来自 createAsyncThunk 或其他 action 的状态更新extraReducers: (builder) => {
builder.addCase(fetchUser.fulfilled, (state, action) => {
state.data = action.payload;
});
}
用于响应”非本 slice 定义”的 action;推荐使用函数形式(builder callback)以支持类型推断

提示:Redux Toolkit 是 Redux 官方推荐的现代写法,新项目应优先使用 RTK 的 configureStorecreateSlicecreateAsyncThunk,它们大幅减少了样板代码并内置了 immer、DevTools 等实用功能。