react 中间件相关的一些源码解析
零、随便说说中间件
在react的使用中,我们可以将数据放到redux,甚至将一些数据相关的业务逻辑放到redux,这样可以简化我们组件,也更方便组件抽离、封装、复用,只是redux不能很好的处理异步,当我们获取接口数据的时候,redux就满足不了我们的需要。然后,中间件就出来了,使用中间件可以满足我们异步获取数据,当然也可以干其他的事;
我们都知道一个数据更新,经过component >> action >> dispatch >> reducers >> state >> store >> component,这样一个过程。其实,中间件的本质就是 把异步的这种情况单独的拿出来处理,然后还是把数据经过redux处理了。也就是说做中间件的关键是先把正常的action 和 异步的action 区分出来,从上边的流程看也只能是action >> dispatch 这一步了。
下边看看中间件相关的一些源码,从createStore开始:
一、createStore
const createStore = (reducers, initialState, enhancer) => {
if (typeof initialState === 'function' && typeof enhancer === 'undefined') {
enhancer = initalState;
initialState = undefined;
}
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
//校验enhancer是否为函数,如果不是函数则抛出异常
throw new Error('Expected the enhancer to be a function.')
}
//如果enhancer存在且为函数,那么则返回如下调用,如果enhancer为applyMiddleware,那么调用则
//是applyMiddleware(createStore)(reducer, preloadedState)。后面讲applyMiddleware再详细讲。
return enhancer(createStore)(reducer, preloadedState)
}
....
// 下边就是没有中间件的时候,返回一些state的方法如:getState, dispatch...
}
这就是做了个区分,有中间件和没中间件的区分,有中间件返回的是中间件代码:enhancer(createStore)(reducer, preloadedState),没有就直接返回一些方法;
二、applyMiddleware
const applyMiddleware = (...middlewares) => (createStore) => (reducer, initial, enhancer) => {
const store = createStore(reducer, initial, enhancer);
let dispatch = store.dispatch;
let chain = [];
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
};
chain = middlewares.map(middleware => middleware(middlewareAPI));// a
dispatch = compose(...chain)(store.dispatch); // b
return { ...store, dispatch };
}
看名字就可以知道这是应用中间件的一个方法,他是将中间件 middlewares 和 store 结合返回一个新的store对象,实际上是对 dispatch 的重写;
结合上边的 createStore 源码我们可以看到,当有中间件的时候 createStore 返回的实际上就是 applyMiddleware 的一个执行结果,从参数看是从第二层的方法开始的,那是因为,我们在执行 createStore之前,会有下面的一步操作:
const enhancer = applyMiddleware(...middlewares)
const store = createStore(reducer, enhancer)
其实可以看到在 applyMiddleware 中利用 createState 重新生成了 store,并对 dispatch 进行了重写:先将每一个中间件都执行一次,参数是 middlewareAPI ,然后将返回的数组, 借助于 compose,以原生 dispatch 为参数执行,返回新的 dispatch,最后替换 store 里的 dispatch 并作为新的 store 返回;这个返回结果实际上就是 createStore 中,有中间件传入时的返回结果。
可能会对 dispatch 重写的过程会不太清楚,下边看看 compose 源码:
三、compose
const compose = (...middlewares) => {
if (middlewares.length === 0) {
return arg => arg;
} else {
const last = middlewares[middlewares.length - 1];
const reset = middlewares.slice(0, -1);
return (args) => rest.reduceRight((composed, f) => f(composed), last(args))
}
}
结合着 applyMiddleware 看这个源码会更好没理解一点。(reducerRight 方法不熟的朋友,百度一下)
当传入中间件数组的时候,返回的是一个带参数的方法, 参数就是相当于上面的 dispatch ,取出最后一个中间件执行,并最为 reducerRight 的 初始值,执行reducerRight 方法;
四、中间件的方法 middleware
const middleware = ({ state, dispatch}) => (next) => (action) => {
if (typeof action === 'funtion') {
return net(action);
}
dispatch(action);
}
中间件的本质:判断你要处理的情况,执行你想要执行的方法,如果是异步,我们 action 通常是方法,所以就执行next,如果不是异步执行的就是原生 dispatch;
中间件的第一层是在 applyMiddleware 中执行的(标注a处),第二层是 applyMiddleware 中 compose 中执行的(标注b处),其实 next 就是原生的 dispatch 或者已经重写的 dispatch (即 middleware 中最后一层的方法);
五、没有了
到目前为止这个中间件相关的源码算是搞完了,理解这些感觉写个中间件基本上没问题,推荐看看 redux-thunk 源码其实很简单,和第四步的差不多;
有一个中间件的小Dome:https://github.com/wayaha/react-demos-middleware
敢不敢点个星!!!
react 中间件相关的一些源码解析的更多相关文章
- TongWEB与JOnAS 对比,国产中间件战斗机东方通TongWEB源码解析
转自网址: http://bbs.51cto.com/thread-489819-1-1.html 首先需要声明的是,本人出于技术爱好的角度,以下的文字只是对所看到的一些情况的罗列,偶尔附加个人的一些 ...
- laravel源码解析
本专栏系列文章已经收录到 GitBooklaravel源码解析 Laravel Passport——OAuth2 API 认证系统源码解析(下)laravel源码解析 Laravel Passport ...
- AspNetCore3.1_Middleware源码解析_3_HttpsRedirection
概述 上文提到3.1版本默认没有使用Hsts,但是使用了这个中间件.看名字就很好理解,https跳转,顾名思义,就是跳转到 https地址. 使用场景,当用户使用http访问网站时,自动跳转到http ...
- AspNetCore源码解析_1_CORS中间件
概述 什么是跨域 在前后端分离开发方式中,跨域是我们经常会遇到的问题.所谓的跨域,就是处于安全考虑,A域名向B域名发出Ajax请求,浏览器会拒绝,抛出类似下图的错误. JSONP JSONP不是标准跨 ...
- .Net Core 中间件之主机地址过滤(HostFiltering)源码解析
一.介绍 主机地址过滤中间件相当于一个白名单,标记哪些主机地址能访问接口. 二.使用 新建WebAPI项目,修改Startup中的代码段如下所示.下面表示允许主机名为“localhost”的主机访问( ...
- React源码解析之React.Children.map()(五)
一,React.Children是什么? 是为了处理this.props.children(this.props.children表示所有组件的子节点)这个属性提供的工具,是顶层的api之一 二,Re ...
- React的React.createContext()源码解析(四)
一.产生context原因 从父组件直接传值到孙子组件,而不必一层一层的通过props进行传值,相比较以前的那种传值更加的方便.简介. 二.context的两种实现方式 1.老版本(React16.x ...
- React的React.createRef()/forwardRef()源码解析(三)
1.refs三种使用用法 1.字符串 1.1 dom节点上使用 获取真实的dom节点 //使用步骤: 1. <input ref="stringRef" /> 2. t ...
- React的Component,PureComponent源码解析(二)
1.什么是Component,PureComponent? 都是class方式定义的基类,两者没有什么大的区别,只是PureComponent内部使用shouldComponentUpdate(nex ...
随机推荐
- [codeforces 852 D] Exploration Plan 解题报告 (二分+最大匹配)
题目链接:http://codeforces.com/problemset/problem/852/D 题目大意: 有V个点,N个队伍,E条边,经过每条边有个时间,告诉你初始N个队伍的位置,求至少有K ...
- [雅礼NOIP2018集训 day3]
考试的时候刚了T1两个小时线段树写了三个子任务结果发现看错了题目,于是接下来一个半小时我自闭了 result=历史新低 这告诉我们,打暴力要端正态度,尤其是在发现自己之前出锅的情况下要保持心态的平和, ...
- Java序列化注意事项
当父类继承Serializeble接口时,所有子类可以被序列化 子类实现了Serializeble接口,父类没有,父类中的属性不能序列化(不报错,数据会丢失),但是在子类中属性仍能正确序列化 如果序列 ...
- Servlet学习(七)——cookie
一.会话技术简介 1.存储客户端的状态 例如网站的购物系统,用户将购买的商品信息存储到哪里?因为Http协议是无状态的,也就是说每个客户访问服务器端资源时,服务器并不知道该客户端是谁,所以需要会话技术 ...
- HDU 1285 确定比赛名次【拓扑排序】
题意:中文的题目-----这道题让我终于明白了那个break的作用---因为题目中有这一句“符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前”@_@ #include<iostrea ...
- 优动漫PAINT中误删工具怎么办?
最近收到一些小伙伴的提问,说我不小心把 XXX工具从面板上删掉了怎么办?本教程就来给大家分 享一下遇到这个问题时的三种解决方法,遇到同样问题的小伙伴们赶紧进来看一下哟! 优动漫PAINT下载:http ...
- 在js中关于同名变量和函数的地位争夺问题
先上一段让大家比较蒙圈的代码,接下来再慢慢讲解 <!DOCTYPE html> <html lang="en"> <head> <meta ...
- nodejs 封装mysql连接池
写在前面的 在nodejs后台代码中,我们总是会和数据库打交道 然而,每次都要写数据库的配置以及连接和断开,不胜其烦 我就封装了一个连接池模块,不足之处还请多多批评 上代码 一下是写在mysqls.j ...
- Java正则类
ava.util.regex 类 Pattern java.lang.Object 继承者 java.util.regex.Pattern 所有已实现的接口: Serializable public ...
- while循环,格式化输出%,运算符,数据类型的转换,编码的初识,
1.内容总览 while循环 格式化输出 运算符 and or not 编码的初识 2. 具体内容 while 循环 where:程序中:你需要重复之前的动作,输入用户名密码时,考虑到while循环. ...