Redux 官方推荐姿势:深入理解 Redux Toolkit 的定位、能力清单与最佳实践
本篇基于 Redux 仓库中的 Redux Toolkit: Overview 文档,系统梳理 Redux Toolkit(下称 RTK)的定义、设计动机与内置 API 全貌,并结合本仓库的源码注释与 examples/counter 官方示例,帮你掌握"为什么 RTK 是编写 Redux 逻辑的官方标准方式"以及"如何在新项目和存量项目中引入 RTK"。
什么是 Redux Toolkit
Redux Toolkit 是 Redux 官方的、有明确设计倾向(opinionated)的、"电池全含"(batteries-included)的高效 Redux 开发工具集。它的目标就是成为编写 Redux 逻辑的标准方式,官方强烈建议使用它。
它包含两类核心能力:
- 一系列简化最常见 Redux 用例的实用函数:包括 store 配置(store setup)、定义 reducers、不可变更新(immutable update)逻辑,甚至可以在不手写任何 action creator 或 action type 的情况下,一次性创建整个"切片"(slice)状态;
- 内置最常用的 Redux 生态插件:如用于异步逻辑的 Redux Thunk 和用于编写 selector 函数的 Reselect,装上即可直接使用,无需再额外安装和接线。
安装方式
Redux Toolkit 以 NPM 包形式提供,可配合模块打包器(module bundler)或直接在 Node 应用中使用:
# NPM
npm install @reduxjs/toolkit
# Yarn
yarn add @reduxjs/toolkit
从本仓库的官方示例可以直接确认当前依赖声明方式,例如 examples/counter/package.json 中声明了 "@reduxjs/toolkit": "^2.1.0",并搭配 react-redux 完成 React 集成。
设计动机:RTK 诞生的三大痛点
Redux 核心库是**刻意保持无倾向(unopinionated)**的——store 如何配置、state 里放什么、reducers 怎么组织,全部由你自己决定。这带来了灵活性,但灵活性并非总是被需要:
有时候我们只想要最简的起步方式,附带合理的开箱即用默认行为;或者在大型应用中反复书写相似代码,希望减少手写的样板代码量。
Redux Toolkit 最初就是为了应对社区对 Redux 的三个常见抱怨而创建的:
- "配置一个 Redux store 太复杂了"(Configuring a Redux store is too complicated)
- "为了让 Redux 干点有用事,我必须添加一堆包"(I have to add a lot of packages to get Redux to do anything useful)
- "Redux 需要太多样板代码"(Redux requires too much boilerplate code)
官方表示,虽然无法解决所有用例,但借鉴 [create-react-app 和 apollo-boost 的"零配置"理念,RTK 提供了一个官方推荐的标准工具组合,处理最常见用例、减少额外决策。
为什么你应该使用 Redux Toolkit
RTK 通过以下方式让编写高质量的 Redux 应用变得更简单、更快速:
- 内置官方推荐的最佳实践(baking in best practices)
- 提供良好的默认行为(good default behaviors)
- 帮助捕获错误(catching mistakes)
- 允许编写更简单的代码
这些收益适用于所有 Redux 用户,不论技能水平或经验深浅;既可以在新项目开始时引入,也可以作为渐进式迁移(incremental migration)的一部分加入现有项目。
使用 RTK 并非强制
原文档特别强调了一个重要边界:
使用 Redux 不要求必须使用 Redux Toolkit。许多现有应用使用其他 Redux 封装库,或完全"手写" Redux 逻辑,如果你更偏好其他做法,完全可以照旧。
但官方立场非常明确:在 Style Guide 中专门设有 "Use Redux Toolkit for Writing Redux Logic" 一节,声明 RTK 是官方推荐的使用 Redux 的工具集,并建议在编写不可变更新逻辑时使用 Immer(最好作为 RTK 的一部分)。换言之:不强制,但强烈建议所有 Redux 应用使用 RTK。
来自源码层的佐证:createStore 已被官方弃用
这一推荐并非停留在文档层面,而是直接写进了本仓库的源码中。查看 src/createStore.ts 可以发现,createStore 函数头上携带了完整的 @deprecated 注释:
/**
* @deprecated
*
* **We recommend using the `configureStore` method
* of the `@reduxjs/toolkit` package**, which replaces `createStore`.
*
* Redux Toolkit is our recommended approach for writing Redux logic today,
* including store setup, reducers, data fetching, and more.
* ...
* `createStore` method from the core `redux` package will not be removed, but we encourage
* all users to migrate to using Redux Toolkit for all Redux code.
*
* If you want to use `createStore` without this visual deprecation warning, use
* the `legacy_createStore` import instead:
*
* `import { legacy_createStore as createStore} from 'redux'`
*/
从源码结构看,可以得出几个确定的实现事实:
createStore不会被移除,功能上仍然可用(在 src/index.ts 中仍正常导出,见第 40-50 行的导出列表);- 若希望在编辑器中不显示弃用警告,可改从
redux包导入legacy_createStore(定义于 src/createStore.ts,它内部只是转调createStore); - 核心包仍然提供
createStore、combineReducers、bindActionCreators、applyMiddleware、compose等基础 API(见 src/index.ts),但官方建议的新代码入口是 RTK 的configureStore。
What's Included:RTK 内置能力清单
这是原文档信息密度最高的部分,以下按 API 逐项说明(其中 createSelector 来自 Reselect 库的再导出):
| API | 作用 | 关键特性 |
|---|---|---|
configureStore() |
包装 createStore,提供简化的配置选项与良好默认值 |
可自动合并 slice reducers;自动加入你提供的任意 Redux 中间件;默认包含 redux-thunk;自动启用 Redux DevTools Extension |
createReducer() |
以"action type → case reducer 函数"的查表形式定义 reducer,替代手写 switch 语句 | 自动使用 Immer 库,让你可以用普通"可变"代码写更简单的不可变更新,例如 state.todos[3].completed = true |
createAction() |
为给定 action type 字符串生成 action creator 函数 | 该函数定义了 toString(),因此可以直接替代 type 常量使用 |
createSlice() |
接受 reducer 函数对象、slice 名称和初始 state 值,自动"切片式"创建状态 | 一次性生成 slice reducer 及对应的 action creators 与 action types |
createAsyncThunk |
接受 action type 字符串和返回 Promise 的函数 | 生成一个 thunk,根据该 Promise 的结果自动 dispatch pending/fulfilled/rejected 三种 action |
createEntityAdapter |
管理 store 中的规范化(normalized)数据 | 生成一组可复用的 reducers 和 selectors |
createSelector |
Reselect 库的 memoized selector 工具 | 由 RTK 再导出,方便直接使用 |
除这些 API 外,RTK 还包含 RTK Query 数据获取 API:一个专为 Redux 打造的强大数据获取与缓存工具,旨在简化 Web 应用中加载数据的常见场景,消除手写数据获取与缓存逻辑的必要性。
官方示例印证:examples/counter 中的现代 Redux 写法
仓库内的 examples/counter 示例完整演示了上文清单中多个 API 的实际用法,可作为可复制的参考实现。
1. 一步完成的 store 配置:configureStore
examples/counter/src/app/store.js 全部代码只有 8 行:
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../features/counter/counterSlice'
export const store = configureStore({
reducer: {
counter: counterReducer
}
})
这一处调用自动完成了传统 createStore 需要手动组合的全部工作:合并 slice reducer(内部走 combineReducers)、注入 redux-thunk 中间件、开发模式下加入捕获意外 mutation 的守卫中间件、接入 Redux DevTools Extension。
2. 一个文件写完整个 feature:createSlice + createAsyncThunk
examples/counter/src/features/counter/counterSlice.js 展示了 RTK 最核心的价值主张——同步 reducer、action 生成、异步逻辑、selector 全部收敛在一个 slice 文件内:
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { fetchCount } from './counterAPI'
const initialState = {
value: 0,
status: 'idle'
}
// thunk 允许执行异步逻辑,可像普通 action 一样 dispatch
export const incrementAsync = createAsyncThunk(
'counter/fetchCount',
async amount => {
const response = await fetchCount(amount)
// 返回的值成为 fulfilled action 的 payload
return response.data
}
)
export const counterSlice = createSlice({
name: 'counter',
initialState,
// reducers 字段:定义 reducer 并自动生成关联 action
reducers: {
increment: state => {
// RTK 借助 Immer,可以用"可变"语法写不可变更新:
// 它检测到 draft state 的变更并生成全新的 immutable state
state.value += 1
},
decrement: state => {
state.value -= 1
},
// 使用 PayloadAction 声明 action.payload 的内容
incrementByAmount: (state, action) => {
state.value += action.payload
}
},
// extraReducers 字段:处理本 slice 之外定义的 action,
// 包括 createAsyncThunk 生成和其他 slice 的 action
extraReducers: builder => {
builder
.addCase(incrementAsync.pending, state => {
state.status = 'loading'
})
.addCase(incrementAsync.fulfilled, (state, action) => {
state.status = 'idle'
state.value += action.payload
})
}
})
export const { increment, decrement, incrementByAmount } = counterSlice.actions
// selector:从 state 中取值
export const selectCount = state => state.counter.value
// 也可以手写 thunk,包含同步与异步逻辑
export const incrementIfOdd = amount => (dispatch, getState) => {
const currentValue = selectCount(getState())
if (currentValue % 2 === 1) {
dispatch(incrementByAmount(amount))
}
}
export default counterSlice.reducer
这段代码印证了概述文档中的几项描述:
createSlice自动生成 action creators:counterSlice.actions直接导出increment、decrement、incrementByAmount,无需手写任何 action type 常量或 action creator 函数;- Immer 支撑的"可变"语法:源码注释明确写道——"Redux Toolkit allows us to write 'mutating' logic in reducers. It doesn't actually mutate the state because it uses the Immer library, which detects changes to a 'draft state' and produces a brand new immutable state based off those changes";
createAsyncThunk的三态生命周期:示例中通过incrementAsync.pending/incrementAsync.fulfilled在extraReducers里更新status字段,正是概述所述"基于 Promise 生成 pending/fulfilled/rejected action"的实际落地;异步请求本身(模拟 500ms 延迟的 Promise)由 examples/counter/src/features/counter/counterAPI.js 提供。
此外,仓库还提供了 TypeScript 版本的同款示例 examples/counter-ts(含 src/app/store.ts 与 src/features/counter/counterSlice.ts),以及配套的测试文件如 counterSlice.spec.js,适合作为对照学习材料。
RTK 与 Redux 核心包的关系与演进
结合仓库中 Why Redux Toolkit is How To Use Redux Today 一篇,可以补全 Overview 的语境:
- RTK 包封装在核心
redux包之上,包含构建 Redux 应用所必需的 API 方法与常用依赖; - 官方立场是:今天编写任何 Redux 逻辑,都应该使用 RTK,核心
redux包单独使用时"仍可用,但已被视为过时(obsolete)"——其全部 API 也从@reduxjs/toolkit再导出,configureStore覆盖了createStore的全部能力并提供更好的默认行为与可配置性; - 对于存量应用,官方建议至少先把
createStore换成configureStore(开发模式中间件能帮你捕获意外 mutation 和可序列化错误),再逐步把最常用的 reducer 迁移到createSlice; - 理解底层概念仍有价值:仓库保留了 Redux Fundamentals 教程 用零抽象展示 Redux 如何运作,但其定位只是学习工具,最终仍会展示 RTK 如何简化那些手写代码。
继续深入的学习路径
Overview 文档指向的完整 RTK 文档在独立站点上,而本仓库内以下页面可作为配套延伸阅读(均相对仓库根目录):
- Why RTK is Redux Today:完整阐述 RTK 如何取代 Redux 核心包;
- Redux Essentials 教程:面向真实应用的现代 Redux 完整教学,含 RTK Query 基础篇 与 进阶篇;
- Migrating to Modern Redux:把各类遗留 Redux 逻辑迁移到现代 RTK 写法的对照指南;
- Style Guide:官方最佳实践汇总,其中 "Use Redux Toolkit for Writing Redux Logic" 一节是 Overview 中推荐立场的出处;
- Writing Logic: Thunks 与 Side Effects Approaches:异步与副作用逻辑的深入实践;
- Writing Tests:测试 Redux 逻辑(含
configureStore搭建测试 store)的方法。
小结
Redux Toolkit 的本质,是把"社区用多年实践验证过的标准做法"固化进官方工具集:一个 configureStore 解决 store 配置,一个 createSlice 同时解决 reducer、action creator、action type 三件套,createAsyncThunk 收敛异步三态管理,createEntityAdapter 与 createSelector 处理规范化数据与派生数据,RTK Query 则接管数据获取与缓存。从 src/createStore.ts 的弃用注释到 examples/counter 的完整示例,仓库源码与官方示例共同印证了同一结论:RTK 依然是"Redux"——单一 store、action 驱动、不可变更新一个不少——只是你为同样结果需要手写的代码大幅减少了。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00