✍️ 源码视角导读
🎯 目标:揭秘 Redux Toolkit(RTK)如何用最少 API 提供最大能力
🧠 关键词:createSlice、createAsyncThunk、Immer、TS 类型推导、代码生成器
💡 Toolkit 的初心:降低心智负担,保留 Redux 精神
Redux 自带门槛:样板代码多、流程复杂、不易入门。
于是我们在设计 Redux Toolkit(RTK)时定下三条目标:
- 减少样板代码(boilerplate)
- 提高开发效率(语法糖 + 类型推导)
- 保留 Redux 的核心原则(单向流、不可变、纯 reducer)
✅ createSlice:用一行代码生成一整套状态逻辑
🧪 使用示例:
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment(state) {
state.value++
},
decrement(state) {
state.value--
},
add(state, action: PayloadAction<number>) {
state.value += action.payload
}
}
})
✅ 自动生成内容:
reducer对象action creator函数action type字符串(如counter/increment)
🔍 源码解析:createSlice 做了哪些事?
路径:@reduxjs/toolkit/src/createSlice.ts
核心流程:
export function createSlice({ name, initialState, reducers }) {
const sliceReducers = {}
// 1️⃣ 自动创建 action types 和 creators
for (const key in reducers) {
const type = `${name}/${key}`
actionCreators[key] = createAction(type)
sliceReducers[type] = reducers[key]
}
// 2️⃣ 创建 reducer(switch case 替代)
const reducer = (state = initialState, action) => {
const caseReducer = sliceReducers[action.type]
return caseReducer ? caseReducer(state, action) : state
}
return { reducer, actions: actionCreators, name }
}
📌 它相当于自动帮你写了:
switch(action.type)分支;- 每个
case的处理函数; - 每个
action的构造器。
并且基于 Immer 做了不可变数据操作的代理(后面详解)。
🔁 Immer 集成:让你“写可变代码”,执行“不可变逻辑”
Toolkit 默认集成了 Immer:
increment(state) {
state.value++ // ✅ 看似可变,其实底层自动代理
}
这是可能的因为 RTK 在内部用 createReducer 包裹你的所有 reducer:
export function createReducer(initialState, builderCallback) {
return function reducer(state = initialState, action) {
return produce(state, draft => {
// 你写的逻辑就作用在 draft 上
builderCallback(draft, action)
})
}
}
💡 实现原理:Immer 会用 Proxy 包裹 draft,记录所有变更,并返回一个不可变的新对象。
🌐 createAsyncThunk:三合一的异步状态方案
使用方式:
export const fetchUser = createAsyncThunk(
'user/fetch',
async (userId: string) => {
const res = await fetch(`/api/user/${userId}`)
return await res.json()
}
)
它自动生成三种 action:
user/fetch/pendinguser/fetch/fulfilleduser/fetch/rejected
你只需在 extraReducers 中处理状态变更即可。
🔍 源码解构:createAsyncThunk 如何实现?
路径:@reduxjs/toolkit/src/createAsyncThunk.ts
核心原理如下:
export function createAsyncThunk(typePrefix, payloadCreator) {
return function thunkCreator(arg) {
return async (dispatch, getState) => {
dispatch({ type: `${typePrefix}/pending` })
try {
const result = await payloadCreator(arg, { dispatch, getState })
dispatch({ type: `${typePrefix}/fulfilled`, payload: result })
return result
} catch (err) {
dispatch({ type: `${typePrefix}/rejected`, error: err })
throw err
}
}
}
}
🧠 本质是封装了 thunk 函数,并自动派发三种生命周期 action。
⚙️ TS 类型系统极致利用:你写越少,它推断越多
PayloadAction 自动推导
add(state, action: PayloadAction<number>) // 自动推断 payload 类型为 number
- action creator 自动生成类型;
- reducer 函数签名自动标注;
- slice 返回的类型可以组合成完整模块定义。
你只需关心业务逻辑,类型推导、声明冗余都交给工具链处理。
📚 常用实践集锦(建议团队统一规范):
| 场景 | 推荐方式 |
|---|---|
| 通用异步请求 | createAsyncThunk |
| 多模块组合 reducer | combineReducers + slice.reducer |
| Action 类型统一管理 | slice 自带,禁止手写字符串 |
| loading/error 管理 | extraReducers 中三态处理 |
| Selector 管理 | 每个 slice 暴露自己的 selector |
| 类型定义 | 使用 PayloadAction<T> 和 RootState 推导 |
🔚 总结:RTK ≠ 新 Redux,而是 Redux 工程化的理性进化
Redux Toolkit 保留了 Redux 的三大核心:
- 单向数据流;
- 状态只读;
- 纯函数 reducer;
但它通过:
- 自动代码生成;
- 更高阶的 API;
- 更严谨的类型系统;
把 Redux 变成了“可落地、可维护、可复用”的工业级状态框架。
⏭️ 下一篇预告
我们终于要收尾本系列的核心部分:
第8篇:《Redux 插件化扩展:如何构建你自己的中间件生态?》
你将亲手实现:
- 权限拦截中间件
- 异步日志中间件
- 节流防抖中间件
- Redux DevTools 自定义桥接