资讯动态

若川博客 Redux 教程:学习 redux 源码整体架构,深入理解中间件原理并动手实现

发布时间:2026/8/23 14:20:58 来源:尧图企业网站定制
若川博客 Redux 教程学习 redux 源码整体架构深入理解中间件原理并动手实现【免费下载链接】blog若川的博客—撰写了学习源码整体架构系列几十篇。组织了源码共读活动每周一起学习200行左右的源码加我微信 ruochuan02 参与。项目地址: https://gitcode.com/gh_mirrors/blog51/blog本文是一篇面向新手的Redux 教程带你学习 Redux 源码整体架构从 Redux 工作流程图建立全局印象到一步步调试createStore、dispatch、subscribe再到深入理解 Redux 中间件原理最后动手实现一个自己的 logger 中间件。全程以「小步调试 图解」的方式展开不堆砌代码零基础也能看懂。这个 Redux 教程适合谁你将学到什么 如果你满足下面任意一条这篇文章就是为你写的面试被问「说说 Redux 中间件的原理」时卡壳用过 Redux但不清楚store.dispatch背后到底发生了什么想读 Redux 源码却不知从哪一行开始下断点。学完本文你将掌握你将学到的内容对应章节Redux 工作流程全貌Redux 工作流程图如何动手调试 Redux 源码调试 Redux 源码的准备工作createStore核心 API 的实现Redux.createStoreRedux 中间件原理AOP 洋葱模型Redux 中间件原理compose函数如何串联中间件Redux.compose 函数vuex 与 redux 的设计对比vuex 与 redux 简单对比 本文配套的全部示例代码与图解都放在 docs/redux/ 目录下建议边看边调试效果最佳。一、先建立整体印象Redux 工作流程图读 Redux 源码最忌讳一上来就逐行抠代码。建议先花 1 分钟看这张 Redux 工作流程图把「Action → 中间件 → Store → Reducer → View」这条主线在脑子里过一遍这张图就是 Redux 源码整体架构的「地图」图中包含四大块Action描述「发生了什么」的普通对象如{ type: INCREMENT }中间件middlewaredispatch的插件执行日志记录、异步请求等「切面」逻辑StoreRedux 的心脏保存唯一的 state提供dispatch、subscribe、getState三个 APIReducers纯函数根据(previousState, action)计算出新的 state。带着这张地图下面所有源码调试都是在这条主线上「放大细节」。二、动手调试 Redux 源码的准备工作看 Redux 源码百读不如一调。调试要领只有四条请记牢赋值语句按F10跳过看返回值即可函数执行用F11步入结合上下文倒推其作用不需要细看的地方按F8直达下一个断点调试完毕按F5刷新重来。准备工作非常简单把 Redux 打包产物开启 sourcemap 后引入一个纯 HTML 计数器页面然后本地起个静态服务# 安装并启动本地静态服务 npm i -g http-server cd examples hs -p 5000打开浏览器F12后你会看到 Chrome DevTools 中 Redux 对象暴露了 6 个 APIapplyMiddleware、combineReducers、compose、createStore等store上有dispatch、subscribe、getState等方法——这就是后面要逐个拆解的目标小技巧右侧Scope面板会显示闭包、全局环境等变量能帮你确认currentState、isDispatching这些闭包私有变量在每一步的取值。计数器示例代码就在 docs/redux/examples/index.1.redux.getState.dispatch.html建议在Redux.createStore(counter)、store.subscribe(render)、store.dispatch(...)三处各打一个断点。三、Redux.createStore理解 store 的核心 APIRedux.createStore的源码结构其实非常「朴素」——它用闭包私有变量保存 state然后返回一个包含 4 个方法的 store 对象// Redux 源码 createStore 的骨架省略参数校验 export default function createStore(reducer, preloadedState, enhancer) { let currentReducer reducer // 当前的 reducer let currentState preloadedState // 当前的 state let currentListeners [] // 订阅函数数组 let isDispatching false // 是否正在 dispatch function getState() {} function subscribe(listener) {} function dispatch(action) {} dispatch({ type: ActionTypes.INIT }) // 初始化时先派发一次 return { dispatch, subscribe, getState, ... } }三个核心 API 的职责一目了然getState()返回闭包中的currentState并禁止在 reducer 执行期间调用subscribe(listener)把监听函数压入nextListeners数组返回一个可取消订阅的函数dispatch(action)先校验 action 是「带 type 的普通对象」再执行currentState currentReducer(currentState, action)最后遍历所有订阅函数依次执行最后返回 action。一句话总结Redux 的状态更新是单向的、同步的——dispatch 触发 reducer 计算新 state再通知所有订阅者。这就是 Redux 状态管理「可预测」的来源。四、Redux 中间件原理applyMiddleware 源码拆解中间件是 Redux 教程的重头戏也是面试高频题。先看一个最经典的 logger 中间件完整示例在 docs/redux/examples/js/middlewares.logger.example.jsfunction logger1({ getState }) { return next action { console.log(will dispatch--1, action) // dispatch 前打日志 const returnValue next(action) // 调用链上的下一个 dispatch console.log(state after dispatch--1, getState()) // dispatch 后看 state return returnValue } }注意这个「返回两层函数」的结构外层接收middlewareAPI含getState、dispatch中层接收next内层才真正处理action。applyMiddleware做的事情可以浓缩为三步源码见 docs/redux/README.md拿到原始 storeconst store createStore(...args)组装中间件链middlewares.map(middleware middleware(middlewareAPI))每个中间件都拿到getState和dispatch用 compose 串联dispatch compose(...chain)(store.dispatch)得到增强后的 dispatch替换掉 store 原生的 dispatch 返回。也就是说Redux.applyMiddleware本身是一个store 增强器enhancercreateStore检测到第三个参数是函数时会执行enhancer(createStore)(reducer, preloadedState)最终返回一个 dispatch 被「层层包裹」的新 store。在浏览器控制台点一下「」按钮你能直观看到三个 logger 的执行顺序是1 → 2 → 3state 回传则是3 → 2 → 1这种「先进后出、层层包裹」的结构就是常说的面向切面编程AOP和洋葱模型——koa 的洋葱模型与此如出一辙。五、Redux.compose 函数中间件串联的关键中间件链能串起来全靠compose这一个函数export default function compose(...funcs) { if (funcs.length 0) return arg arg if (funcs.length 1) return funcs[0] return funcs.reduce((a, b) (...args) a(b(...args))) }看不懂reduce那行我们可以从最朴素的例子一步步演化。先看一个需求把数字乘 10、加 10、减 2且每一步都想打日志const calc (num) num * 10 10 - 2 // 不好扩展无法在每步插入日志拆成三个函数后手动组合minus(add(multiply(10)))。再写一个「组合器」const compose (f, g, h) x f(g(h(x))) // 只支持 3 个函数最后用reduce泛化到任意个函数——a是上一次组合的结果b是下一个函数const compose (...funcs) funcs.reduce((a, b) x a(b(x))) // compose(f, g, h) 最终得到 (...args) f(g(h(...args)))从右到左执行演化过程的每一步都可运行代码都放在 docs/redux/examples/compose/ 目录compose.0.calc.js到compose.5.reduce.js共 6 个文件强烈建议按编号顺序逐个跑一遍compose就彻底通了。理解了 compose再来看这张 Redux 中间件原理图洋葱模型瞬间具象化用户触发enhancedStore.dispatch(action)实际进入第一个中间件每个中间件的next指向下一个中间件最里层的store.dispatch(action)是没有中间件增强的原生 dispatch调用「下行」按 1→2→3「上行」按 3→2→1与 Koa 洋葱模型同构。六、combineReducers 与 bindActionCreators除了中间件Redux 还有两个高频 API原理一句话就能讲清combineReducers(reducers)把多个小 reducer 合并成一个总的combination函数。它遍历每个 key 执行reducer(previousStateForKey, action)用nextStateForKey ! previousStateForKey判断是否变化——没有变化就返回旧引用这是 React 组件跳过无谓渲染的关键优化。bindActionCreators(actionCreators, dispatch)把 action 创建函数「绑定」dispatch。传函数返回函数传对象则遍历绑定返回一个「点击即派发」的boundActionCreators对象主要供 react-redux 等上层库使用。可运行示例见 docs/redux/examples/index.4.html 与 docs/redux/examples/js/index.4.bindActionCreators.combineReducers.example.js。七、vuex 与 redux 简单对比学过 vuex 的同学做一张对比表就能把 Redux 的设计思想钉进记忆维度vuexredux实现风格以构造函数class Store为主函数式编程 闭包与视图层耦合与 Vue 强耦合框架无关React/小程序/jQuery 皆可扩展机制插件plugins.forEach(plugin plugin(this))把 store 实例交给插件中间件AOP 洋葱模型通过增强 dispatch 实现上手难度相对简单涉及高阶函数、纯函数、函数组合门槛略高正因为 Redux 中间件本质是「增强器」任何人都可以实现自己的 store enhancer这也是 Redux 生态thunk、saga 等如此繁荣的根源。八、总结动手实现你的第一个 Redux 中间件面试被要求「手写一个 Redux 中间件」时背下这三段代码就够了// 1. 一个最简单的中间件 function logger({ getState }) { return next action { const returnValue next(action) return returnValue } } // 2. compose从右到左组合函数 const compose (...funcs) funcs.reduce((a, b) x a(b(x))) // 3. 用 applyMiddleware 增强 storedispatch 即走中间件链 const store Redux.createStore(reducer, Redux.applyMiddleware(logger)) store.dispatch({ type: INCREMENT })再回头看一遍 Redux 工作流程图整个数据流是不是清晰多了最后附上本文用到的全部学习资料都可直接在仓库中打开 源码解析全文docs/redux/README.md 计数器 dispatch 调试示例docs/redux/examples/index.1.redux.getState.dispatch.html applyMiddleware compose 调试示例docs/redux/examples/index.2.redux.applyMiddleware.compose.html logger 中间件三件套docs/redux/examples/js/middlewares.logger.example.js compose 演化 6 步走docs/redux/examples/compose/ 全部图解原图docs/redux/images/本文是「学习源码整体架构系列」的第 8 篇前 7 篇分别拆解了 jQuery、underscore、lodash、sentry、vuex、axios、koa。想看更多源码系列文章可 clone 本仓库浏览 docs/ 目录git clone https://gitcode.com/gh_mirrors/blog51/blog。动手调试几遍你就再也不会惧怕 Redux 源码了 【免费下载链接】blog若川的博客—撰写了学习源码整体架构系列几十篇。组织了源码共读活动每周一起学习200行左右的源码加我微信 ruochuan02 参与。项目地址: https://gitcode.com/gh_mirrors/blog51/blog创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价