4、Redux 核心架构源码解读(下)——中间件机制的实现与函数式魅力
✍️ 模拟 Redux 创始人 Dan Abramov 内心设计思维
🎯 聚焦:
applyMiddleware
如何劫持dispatch
?🔍 关键词:中间件链、函数组合、dispatch 增强、洋葱模型(Onion Model)
🍩 我们为什么设计 middleware?
Redux 的原始设计只处理同步状态流,但在真实业务中我们还需要:
- 发起异步请求(如
fetch
) - 记录日志、性能分析
- 上报埋点、安全审计
- 报错捕获
- 权限拦截 / 重定向跳转
你不希望把这些“副作用逻辑”塞到 reducer 里,于是我们设计了一个**“dispatch 增强系统”**:
中间件(Middleware)本质上是一个“可插拔的 dispatch 劫持器”。
🧪 看例子:如何写一个日志中间件?
const logger = store => next => action => {
console.log('dispatching', action)
const result = next(action)
console.log('next state', store.getState())
return result
}
🔍 结构拆解:
middleware = store => next => action => {}
-
store
:当前 Redux store 实例 -
next
:下一个中间件或原始dispatch
-
action
:你要分发的 action
这个结构,其实就是洋葱模型函数链式封装。
🧰 applyMiddleware
的源码实现(简化版)
function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState) => {
const store = createStore(reducer, preloadedState)
let dispatch = store.dispatch
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
const chain = middlewares.map(mw => mw(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return { ...store, dispatch }
}
}
🧠 深度解读每一步
🧩 middlewareAPI
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
👉 把最基本的能力(状态获取、触发 action)暴露出去给中间件用,但通过闭包劫持 dispatch
,确保是增强后的 dispatch。
🧰 compose
:中间件链的秘密武器
function compose(...funcs) {
return funcs.reduceRight((a, b) => (...args) => b(a(...args)))
}
这个函数做了什么?
compose(fn1, fn2, fn3)(dispatch)
// 相当于 fn1(fn2(fn3(dispatch)))
每个中间件包裹住下一个中间件,最终将 action 传给原始 dispatch。这就是**“洋葱模型”**。
🧪 举个更形象的例子:
我们注册了如下中间件:
applyMiddleware(logger1, logger2, thunk)
会得到如下执行链:
dispatch = logger1(logger2(thunk(dispatch)))
当你调用 store.dispatch(action)
:
-
logger1
先执行,记录日志; - 再交给
logger2
做拦截; - 最后进入
thunk
判断是否为函数; - 最终调用原始 reducer。
🔄 我们这样设计的原因只有一个:高度可组合性
中间件是 Redux 的“插件系统”,但我们坚持这几点:
原则 | 解释 |
---|---|
无依赖注入 | middleware 只依赖 getState 和 dispatch
|
无状态 | 中间件函数本身是无状态函数,便于复用、测试 |
只包一次 dispatch | 所有中间件最终作用于 dispatch ,逻辑单一清晰 |
🔥 自定义中间件场景推荐:
场景 | 建议实现方式 |
---|---|
打印日志 | loggerMiddleware |
异步请求 |
redux-thunk / redux-saga
|
权限验证 | authMiddleware |
请求去重 | requestCacheMiddleware |
报错捕获上报 | errorCaptureMiddleware |
多语言替换 | i18nMiddleware |
🪢 总结:Redux 中间件的真正威力
中间件是 Redux 最被模仿的部分(如 Express/Koa 的中间件链),其威力来源于三点:
- 函数式组合:易读、可测试、抽象度高;
- 扩展性强:可插拔、无副作用污染;
- 执行链可控:你可以控制 action 的完整生命周期。
它将“架构的中间环节”变成了“第一等公民”。
⏭️ 下一篇预告
我们即将踏入 UI 层的 Redux 世界,下一篇将深入剖析:React-Redux 是如何用 Context + 高阶组件连接 UI 与 Redux 的?
你会看到
connect(mapStateToProps)
背后究竟做了哪些性能优化与底层 magic。