redux源码图解:createStore 和 applyMiddleware
在研究 redux-saga
时,发现自己对 redux middleware
不是太了解,因此,便决定先深入解读一下 redux
源码。跟大多数人一样,发现 redux源码 真的很精简,目录结构如下:
|—— utils
|—— warnings.js
|—— applyMiddleware.js
|—— bindActionCreator.js
|—— combineReducers.js
|—— compose.js
|—— createStore.js
|—— index.js
在 index.js
中导出了5个模块,即外部可用的:
export {
createStore,
combineReducers,
bindActionCreators,
applyMiddleware,
compose
}
然而,当真正解读的时候,发现还真是有点吃不消,经过几天的硬啃之后,只能说:终于等到你,还好我没放弃。。。(自带BGM)
这里,我可能不会仔细去分析它的源码,但会就自己的理解进行梳理概括,具体的对我很有帮助的文章会放到结尾参考处。
首先是对 createStore
、 applyMiddleware
及 compose
的梳理,因为这3个模块存在相互调用的关系,其关系图如下(高清图请查看 redux源码图解之createStore和applyMiddleware):
1. 每个模块的作用
createStore
的函数的作用就是生成一个 store 对象,这个对象具有5个方法:
return {
dispatch, // 传入 action,调用 reducer 及触发 subscribe 绑定的监听函数
subscribe,
getState,
replaceReducer, // 用新的 reducer 代替当前的 reducer,使用不多
[$$observable]: observable
}
而 applyMiddleware
函数的作用就是对 store.dispatch
方法进行增强和改造,使得在发出 Action 和执行 Reducer 之间添加其他功能。
compose
函数则是 applyMiddleware
函数的核心,其会形成串联的函数调用关系,用于增强 dispatch
方法。
2. 模块之间的调用关系
(i) 首先,createStore
模块会对传入的参数进行判断,分别处理不同参数的情况,当传入 applyMiddleware(...middleware)
的时候,就会返回 applyMiddleware(...middleware)
执行之后的高阶函数,即:
// createStore.js
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
// 这里的 enhancer 是 applyMiddleware(...) 执行后的高阶函数,传参无 enhancer
return enhancer(createStore)(reducer, preloadedState)
}
(ii)然后,就进入了 applyMiddleware
模块内部的逻辑,从 createStore
返回的高阶函数,其传入的参数是没有 enhancer
的,因此走的是 createStore
函数中没有传入 enhancer 的逻辑,用于先获得没有中间件时返回的 store。
// applyMiddleware.js
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
let dispatch = store.dispatch
let chain = [] // 用于存放获取了store的中间件数组
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
(iii)接着,获取最原始的 store 的 getState
和 dispatch
,封装于 middlewareAPI
对象。将该对象传入中间件 middleware
中,形成中间件数组 chain
。
其中,middleware
的范式是:(store) => (next) => (action) => {}
,将 middlewareAPI
传入middleware
后,中间件便获得了 {getState, dispacth}
。至此,chain 中间件数组中包含的每个中间件的形式都变成了 (next) => (action) => {}
的形式。
(iiii)最后,调用 compose
函数,如 chian = [middleware1, middleware2, middleware3]
,则 dispatch = compose(...chain)(store.dispatch)
,即执行 middleware1(middleware2(middleware3(store.dispatch)))
,然后赋值给 dispatch
。
总之,不管是否有
applyMiddleware
,createStore
的结果都是输出一个 store 对象,而applyMiddleware
则可以对 store 对象中的dispatch
进行改造。
3. 参考
- redux middleware 详解
- Redux源码分析(一):主要架构,createStore.js,applyMiddleware.js和compose.js部分
- Redux 入门教程(二):中间件与异步操作
redux源码图解:createStore 和 applyMiddleware的更多相关文章
- redux源码阅读之compose,applyMiddleware
我的观点是,看别人的源码,不追求一定要能原样造轮子,单纯就是学习知识,对于程序员的提高就足够了.在阅读redux的compose源码之前,我们先学一些前置的知识. redux源码阅读之compose, ...
- Redux 源码解读--createStore,js
一.依赖:$$observable.ActionTypes.isPlainObject 二.接下来看到直接 export default 一个 createStore 函数,下面根据代码以及注释来分析 ...
- Redux源码分析之createStore
接着前面的,我们继续,打开createStore.js, 直接看最后, createStore返回的就是一个带着5个方法的对象. return { dispatch, subscribe, getSt ...
- Redux源码分析之applyMiddleware
Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...
- redux源码学习笔记 - createStore
本篇是学习redux源码的一些记录,学习的redux版本是^4.0.1. 在页面开发时,需要管理很多状态(state),比如服务器响应,缓存数据,UI状态等等···当页面的庞大时,状态就会变的混乱.r ...
- Redux源码分析之基本概念
Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...
- Redux源码分析之bindActionCreators
Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...
- Redux源码分析之combineReducers
Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...
- Redux源码分析之compose
Redux源码分析之基本概念 Redux源码分析之createStore Redux源码分析之bindActionCreators Redux源码分析之combineReducers Redux源码分 ...
随机推荐
- 室内Vary 渲染部分作品
室内Vary 渲染倍分作品
- vue2.0项目 calendar.js(日历组件封装)
最近一直闲来无事,便寻思着做一下自己的个人项目,也想说能使用现在比较流行的一些mvvm框架来做,于是就选用了这样的一个技术栈vue2.0+vue-router+vuex+webpack来做,做得也是多 ...
- linux常用命令 echo输出命令
echo输出命令 'echo [选项] [输出内容]' 选项 '-e' 支持反斜线控制的字符转换 控制字符 \a 输出警告音 \b 退格键,也就是向左删除键 \n 换行符 \r 回车键 \t 制表符 ...
- 网页链接跳转qq聊天界面以及QQ群是什么实现的
网页可以唤起QQ群,这我们都知道可以做到,那如何唤起呢?下面就做一个简单的介绍,希望可以帮助到有需要的朋友 1.官方提供的几种加群的链接 官方的加群代码的获取前提是我们具有权限(也就是群主或管理权限) ...
- 列举至少3种Support包中提供的布局或工具
android.support.v7.widget.CardView 继承自FrameLayout并实现了圆角和阴影效果,常用于ListView或RecyclerView中Item布局的根节点 示例代 ...
- HTML中data-* 属性
使用 data-* 属性来嵌入自定义数据: <ul><li data-animal-type="bird">Owl</li><li dat ...
- Java容器解析系列(7) ArrayDeque 详解
ArrayDeque,从名字上就可以看出来,其是通过数组实现的双端队列,我们先来看其源码: /** 有自动扩容机制; 不是线程安全的; 不允许添加null; 作为栈使用时比java.util.Stac ...
- 转载:入门Webpack,看这篇就够了
写在前面的话 阅读本文之前,先看下面这个webpack的配置文件,如果每一项你都懂,那本文能带给你的收获也许就比较有限,你可以快速浏览或直接跳过:如果你和十天前的我一样,对很多选项存在着疑惑,那花一段 ...
- nginx申请并配置免费https
你还在让你的网站裸奔在网络上吗?在这里我们将搭建免费版HTTPS,免费的,免费的,免费的,重要的事情说三遍,申请来源为letsencrypt, 超文本传输协议HTTP协议被用于在Web浏览器和网站服务 ...
- 使用 ado.net访问数据库
一.ADO.NET :用于连接数据库的技术 1.ADO.NET分为两大组件 DataSet:数据集 .NET FRAMWORK :用于连接到数据库,发送命令,检索结果 2.ADO. ...