🧩 Redux 番外篇 5:Redux Toolkit 源码架构解构——从 store.ts 到 createAsyncThunk

187 阅读3分钟

✍️ 源码导读分析 🎯 目标:让你看懂 Redux Toolkit 如何做到“语法极简 + 功能极强” 🧠 关键词:RTK、createSlice、createAsyncThunk、Immer、TS 类型系统、自动生成


🔍 Redux Toolkit 架构模块总览

Redux Toolkit 是以模块组装式架构构建的,每个核心功能都来源于一个独立文件:

/src
├── configureStore.ts       // store 创建逻辑
├── createSlice.ts          // 自动生成 reducer + actions
├── createAsyncThunk.ts     // 异步 action 工厂
├── createReducer.ts        // 支持 Immer 的 reducer 构建器
├── createAction.ts         // 类型安全 action 工具
├── middleware/
│   └── serializability.ts  // DevTools & persist 支持

🧱 一、configureStore.ts:一个 store、多个增强

export function configureStore(options: ConfigureStoreOptions) {
  const middleware = options.middleware ?? getDefaultMiddleware()
  const enhancer = applyMiddleware(...middleware)

  const store = legacyCreateStore(options.reducer, options.preloadedState, enhancer)

  return store
}

🧠 实现逻辑:

  • getDefaultMiddleware() 会自动注入 thunk、serializability 检查等
  • 如果你传入 middleware: getDefaultMiddleware({ serializableCheck: false }),就可覆盖默认行为
  • 内部复用的是经典的 Redux createStore + applyMiddleware + compose

✅ 工程收益:

  • 封装一致行为(例如 DevTools 开启、默认中间件)
  • 类型系统自动补全 dispatch、getState 类型

🧩 二、createSlice.ts:动作、类型、reducer 一气呵成

使用示例:

const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment(state) {
      state.value++
    }
  }
})

实现思路(关键简化版):

function createSlice(options) {
  const actions = {}
  const reducersMap = {}

  for (const key in options.reducers) {
    const type = `${options.name}/${key}`
    actions[key] = createAction(type)
    reducersMap[type] = options.reducers[key]
  }

  const reducer = createReducer(options.initialState, builder => {
    for (const type in reducersMap) {
      builder.addCase(type, reducersMap[type])
    }
  })

  return { reducer, actions, name: options.name }
}

🧠 精妙之处:

  • 自动生成 type: 'sliceName/actionName' 的字符串
  • 使用 createAction() 生成可推导类型的 action creator
  • 最终 reducer 使用 createReducer 构建(内部集成 Immer)

🧪 三、createAsyncThunk.ts:异步处理自动三态化(pending / fulfilled / rejected)

使用:

const fetchUser = createAsyncThunk('user/fetch', async (id) => {
  const res = await fetch(`/api/user/${id}`)
  return await res.json()
})

实现核心:

function createAsyncThunk(typePrefix, payloadCreator) {
  return function thunk(arg) {
    return async (dispatch, getState) => {
      dispatch({ type: `${typePrefix}/pending` })
      try {
        const result = await payloadCreator(arg, { dispatch, getState })
        dispatch({ type: `${typePrefix}/fulfilled`, payload: result })
      } catch (err) {
        dispatch({ type: `${typePrefix}/rejected`, error: err })
      }
    }
  }
}

✅ 工程亮点:

  • 自动三态化(你不再需要手写 loading、error)
  • 可配合 extraReducers 优雅接入 reducer
  • 类型联动(action.payload 类型自动传递)

💡 四、Immer 集成:用“可变写法”实现“不可变 reducer”

Redux Toolkit 默认使用 immer 封装 reducer:

increment(state) {
  state.value++
}

🔍 背后原理:

function createReducer(initialState, builderCallback) {
  return function reducer(state = initialState, action) {
    return produce(state, draft => {
      // 用户写的 reducer 被套在 produce 内部
      builderCallback(draft, action)
    })
  }
}

🔧 produce() 会基于 Proxy 生成“不可变快照”,这是 Redux Toolkit 能实现“代码变简单,逻辑依然安全”的关键。


🧠 五、类型系统的联动与设计精髓

RTK 最难、最巧妙的部分在于 类型自动联动

1. PayloadAction 推导

add(state, action: PayloadAction<number>)

💡 PayloadAction<T> 本质是:

interface PayloadAction<T> {
  type: string
  payload: T
}

你写了 reducers: { add(state, action) { ... } },RTK 会自动在 compile 时约束 action.payload 类型。


2. 推导 Action Creators 类型

const slice = createSlice({ ... })
slice.actions.increment // ➜ () => { type: 'slice/increment' }
  • 自动注入 payload 参数(如果 reducer 需要)
  • 自动补齐 dispatch 类型提示
  • 无需写 type 字符串常量

🔬 六、源码质量亮点总结

模块实现精度特点说明
createSlice函数式 + 类型双封装自动生成 reducers + actions
createAsyncThunk异步流程自动三态dispatch 流封装,结构优雅
createReducer支持 immer可变写法 + 不可变数据合体
configureStore精准封装 Redux 核心默认中间件、DevTools、类型集成

RTK 的核心哲学是:

“你写得少,但它不会少做任何事。”


🔚 总结:Redux Toolkit 是一次工程理性的胜利

相比经典 Redux 的冗长样板,RTK:

  • 保留了 Redux 的所有架构优势(单向流、纯函数、调试性强)
  • 通过源码结构清晰、接口设计极致,构建了现代前端状态管理的标准工具链
  • 做到类型安全、代码简洁、逻辑解耦、扩展强大四者兼得

⏭️ 下一篇预告

最后一篇,我们将深入团队实战与大型项目血泪教训:

番外篇 6:《Redux 工程实战集锦:企业常见的 7 个反模式与 7 个最佳实践》 内容包含:

  • 真实踩坑示例:dispatch 滥用、状态结构混乱、组件层 state 不清晰
  • 最佳实践:状态模块拆分策略、selector 优化技巧、异步状态统一管理方案
  • 团队规范建议 + 架构模板参考