✍️ 手把手源码实现
🎯 目标:掌握 Redux 的中间件机制,构建适用于权限、节流、日志、DevTools 的插件
🧠 关键词:applyMiddleware、compose、函数链、action 拦截、增强 dispatch
🧩 Redux 为什么能“插插件”?
Redux 的中间件机制是基于函数组合 + dispatch 劫持完成的。 你可以像搭积木一样,组合出任意逻辑:
const middleware = store => next => action => {
// 插件逻辑
return next(action)
}
最终形成:
dispatch = logger(auth(throttle(originalDispatch)))
这套机制具有:
- ⛓️ 链式组合(Onion Model)
- 🔀 传入原始 dispatch,传出增强版 dispatch
- 🎯 可任意扩展、插拔、不污染主流程
⚙️ 中间件机制回顾:applyMiddleware + compose 的魔法
Redux 源码中,applyMiddleware 实际就是:
function applyMiddleware(...middlewares) {
return createStore => (...args) => {
const store = createStore(...args)
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 }
}
}
你只需要记住一句话:
中间件是用来“增强 dispatch”的。
✍️ 实战一:权限中间件 authMiddleware
const authMiddleware = store => next => action => {
if (action.meta?.requiresAuth && !store.getState().auth.loggedIn) {
console.warn('未登录,操作被拦截')
return { type: 'AUTH_BLOCKED' }
}
return next(action)
}
📌 说明:
- 支持判断 meta 字段
- 用于拦截删除、编辑等需登录操作
✍️ 实战二:节流防抖中间件 throttleMiddleware
const actionCache = new Map()
const throttleMiddleware = store => next => action => {
const key = action.type + JSON.stringify(action.payload)
if (actionCache.has(key)) return // 丢弃重复 action
actionCache.set(key, true)
setTimeout(() => {
actionCache.delete(key)
}, 1000)
return next(action)
}
📌 说明:
- 对某些高频操作(如输入、点赞)进行节流
- 控制 1s 内不重复发起相同 action
✍️ 实战三:异步日志上报 middleware
const logMiddleware = store => next => action => {
const result = next(action)
setTimeout(() => {
navigator.sendBeacon('/log', JSON.stringify({
type: action.type,
state: store.getState(),
timestamp: Date.now()
}))
}, 0)
return result
}
📌 说明:
- 异步发送日志,不阻塞主流程
- 使用
sendBeacon避免在 unload 阶段丢失数据
✍️ 实战四:DevTools 自定义桥接 middleware
const devToolsMiddleware = store => next => action => {
const result = next(action)
if (window.__MY_DEVTOOLS__) {
window.__MY_DEVTOOLS__.log({
type: action.type,
payload: action.payload,
newState: store.getState()
})
}
return result
}
📌 说明:
- 允许你打造自定义 DevTools 面板
- 可以将状态流传输到浏览器插件、跨窗口、Node 控制台等
🧠 高级扩展:中间件组合策略与调度顺序建议
| 插件类型 | 放前面还是后面 | 原因说明 |
|---|---|---|
| 鉴权类 | 前面 | 最早拦截非法操作 |
| 埋点/日志类 | 后面 | 需要获取执行后的 state |
| 节流防抖类 | 前面 | 控制是否执行当前 action |
| loading 控制 | 前中段 | 尽早派发 loading 开启,等待后续 fulfilled/rejected |
建议中间件顺序:
applyMiddleware(
throttleMiddleware,
authMiddleware,
loadingMiddleware,
asyncMiddleware, // thunk/saga
logMiddleware,
devToolsMiddleware
)
🔧 多中间件组合封装:你的 Redux 插件系统可以模块化管理
export const myMiddlewares = [
throttleMiddleware,
authMiddleware,
logMiddleware,
devToolsMiddleware
]
结合:
const store = configureStore({
reducer,
middleware: getDefaultMiddleware().concat(myMiddlewares)
})
🧩 进阶:你也可以创建“带配置的中间件工厂”
const createTrackingMiddleware = (tracker) => store => next => action => {
const result = next(action)
tracker.track(action.type)
return result
}
const tracker = { track: (type) => console.log('上报:', type) }
const trackingMiddleware = createTrackingMiddleware(tracker)
中间件也是“可参数化的函数”,你可以封装出「通用能力 + 项目定制」的架构利器。
🔚 总结:中间件 = Redux 插件系统的本质
Redux 本身是极简核心:只做同步状态更新。 但它留出了中间件这个“扩展插槽”,你可以构建自己的:
- 权限策略系统
- 请求队列系统
- 日志审计系统
- 节流防抖系统
- 自动恢复/持久化系统
- DevTools 桥接机制
你构建的不再只是“业务代码”,而是「前端状态系统的内核生态」。
⏭️ 下一篇预告
是时候回归初心,用代码封装你自己的 Redux 实现了!
第9篇:《最简 Redux 实现:从 0 构建可用的状态容器》 从 createStore 到中间件链,全手写复现,只用不到 100 行代码。