Middleware 机制深度解析
Middleware 扩展 dispatch:在 action 到达 reducer 之前/之后插入逻辑(日志、异步、thunk、saga 入口等)。实现靠 applyMiddleware + 函数柯里化洋葱模型。
源码:packages/redux/src/applyMiddleware.ts、middleware/*.ts(若分包)。
1. 心智模型:洋葱
text
dispatch = middlewareN( ... middleware1( store.dispatch ) ... )一次 dispatch(action) 从最外层 middleware 进入,可:
- 改写
action(或 dispatch 多个 action) - 异步后再
dispatch - 调用
next(action)交给内层,最终到真实 reducer
next:链上向内;store:getState、dispatch(注意递归 dispatch)。
2. 为何三层柯里化 (api) => (next) => (action) => {}
| 层 | 绑定时机 |
|---|---|
最外 api | 创建时拿到 dispatch/getState,可挂一次性资源 |
next | 链上相邻一环 |
最内 action | 每次 dispatch 调用 |
这样 middleware 工厂只创建一次,避免每次 dispatch 重建闭包(见 08 §三)。
3. applyMiddleware 流程(总结)
createStore先创建裸 store。middlewareAPI = { getState, dispatch: (a) => dispatch(a) }(dispatch 可替换为增强版)。- 每个 middleware 得到
next链。 - 最外层
dispatch作为 store 的dispatch导出。
4. 常见 Middleware 职责
| 名称 | 作用 |
|---|---|
| redux-thunk | action 为函数时执行 (dispatch, getState) => … |
| redux-logger | 记录 prev/next state |
| redux-saga | 通常独立运行,监听 store(不严格在 apply 链内) |
RTK 默认内置 thunk;复杂异步更推荐 RTK Query 或 saga。
5. 与 Reducer 边界
| 放 middleware | 放 reducer |
|---|---|
| 请求、定时器、路由 | 根据 action 计算 state |
| 多步 dispatch | 不可变更新 |
违反会导致难以测试、时间旅行失效。
6. 类型(Redux 5)
MiddlewareAPI、Dispatch、Middleware 泛型改进,使 dispatch 可表达 thunk 返回类型;细节见 07。
7. 总结
Middleware = 可组合的 dispatch 装饰器;applyMiddleware 在创建 store 时一次性织链。理解洋葱后,读 thunk 源码只需几十行。