8、Redux 插件化扩展指南——打造你自己的中间件生态系统

103 阅读3分钟

✍️ 手把手源码实现

🎯 目标:掌握 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 行代码。