7、Redux Toolkit 深度解构——设计、源码与工程精髓

199 阅读3分钟

✍️ 源码视角导读

🎯 目标:揭秘 Redux Toolkit(RTK)如何用最少 API 提供最大能力

🧠 关键词:createSlice、createAsyncThunk、Immer、TS 类型推导、代码生成器


💡 Toolkit 的初心:降低心智负担,保留 Redux 精神

Redux 自带门槛:样板代码多、流程复杂、不易入门。

于是我们在设计 Redux Toolkit(RTK)时定下三条目标:

  1. 减少样板代码(boilerplate)
  2. 提高开发效率(语法糖 + 类型推导)
  3. 保留 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/pending
  • user/fetch/fulfilled
  • user/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
多模块组合 reducercombineReducers + 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 自定义桥接