redux 思考以及源码解析
1. 基本概念
redux有以下几个基本概念:
1.1. action
action: 是一个对象,对一个行为的基本描述
{type:'add',todo
}
1.2 action creator
一个函数,返回结果是一个action
function add (todo) {return {type: 'add',todo}}
1.3 reducer
真正更新数据操作的函数
let todoReducer = function (state = todoList, action) {switch (action.type) {case 'add':return [...state, action.todo]case 'delete':return state.filter(todo => todo.id !== action.id)default:return state}
}
store: 只有一个
dispatch:触发一个action
subscribe : 订阅store
getState :获得当前的state
replaceReducer :更换reducer
observable :
2. createStore源码解析
export default function createStore(reducer, preloadedState, enhancer) {if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {enhancer = preloadedStatepreloadedState = undefined}if (typeof enhancer !== 'undefined') {if (typeof enhancer !== 'function') {throw new Error('Expected the enhancer to be a function.')}return enhancer(createStore)(reducer, preloadedState)}
如果 preloadState是函数,并且enhancer为空, enhancer =preloadState
接着,如果有enhancer ,那么 return enhancer(createStore)(reducer, preloadedState)
结合我们的调用分析一下我们通常调用的代码:
let store = createStore(todoReducer, applyMiddleware(thunk,logger))
是怎么来的。
preloadState是函数,并且enhancer为空, enhancer = applyMiddleware(thunk,logger)return enhancer(createStore)(reducer, preloadedState) = return applyMiddleware(thunk,logger)(createStore)(reducer, preloadedState)
3. applymiddleware 源码解析
中间件是通过next来进入下一个中间件的,执行完毕后,会调用最原始的store.disptach,reducer执行完毕后,该次操作并没有完毕, 还会依次返回到中间件。
任何一个中间件不next ,其后面的中间件都不会执行
export default function applyMiddleware(...middlewares) {return (createStore) => (reducer, preloadedState, enhancer) => {const store = createStore(reducer, preloadedState, enhancer)let dispatch = store.dispatchlet chain = []const middlewareAPI = {getState: store.getState,dispatch: (...args) => dispatch(...args)}chain = middlewares.map(middleware => middleware(middlewareAPI))dispatch = compose(...chain)(store.dispatch)return {...store,dispatch}}
}
所有中间件的格式都是第一层参数都是 {disptach,getState}这个样子
({dispatch, getState} ) => next => action => {......}
第二句就是把每个middleware传入参数,初始化一下,这里的最大作用就是利用闭包,让每个middleware拥有同一份disptach和getState的引用。
核心的一句:
dispatch = compose(...chain)(store.dispatch)
这样的函数是整个作为前面一个函数的next参数存在的,所以你每次next(action)实际上就是进入下一个中间件的执行体,
3.1 redux-thunk的解析
function createThunkMiddleware(extraArgument) {return ({ dispatch, getState }) => next => action => {if (typeof action === 'function') {return action(dispatch, getState, extraArgument);}return next(action);};
}const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;export default thunk;
4. compose源码解析
其作用是把一系列的函数,组装生成一个新的函数,并且从后到前,后面参数的执行结果作为其前一个的参数。
如:
compose(f, g, h) is identical to doing* (...args) => f(g(h(...args))).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)))
}
把b(...args)作为参数传入a a(b(...args))再执行
我们知道reduce函数返回是一个值。上面函数传入的回调函数是(a, b) => (...args) => a(b(...args))其中a是当前的累积值,b是数组中当前遍历的值。假设调用函数的方式是compose(f,g,h),首先第一次执行回调函数时,a的实参是函数f,b的实参是g,第二次调用的是,a的实参是(...args) => f(g(...args)),b的实参是h,最后函数返回的是(...args) =>x(h(...args)),其中x为(...args) => f(g(...args)),所以我们最后可以推导出运行compose(f,g,h)的结果是(...args) => f(g(h(...args)))。发现了没有,这里其实通过reduce实现了reduceRight的从右到左遍历的功能,但是却使得代码相对较难理解。在Redux 1.0.1版本中compose的实现如下:
export default function compose(...funcs) {return funcs.reduceRight((composed, f) => f(composed));
}
5. bindActionCreator源码解析
bindActionCreators:对disptach的一种封装,可以直接执行或者通过属性方法的调用隐式的调用dispatch,而不用显式调用dispacth
例子:
// action creater
let actionCreaters = {add: function (todo) { //添加return {type: 'add',todo}}, delete: function (id) {return {type: 'delete',id}}
}let boundActions = bindActionCreators(actionCreaters, store.dispatch)
boundActions.add({id: 12,content: '睡觉觉'
})let boundAdd = bindActionCreators(actionCreaters.add, store.dispatch)
boundAdd({id: 13,content: '陪媳妇'
})
源码:
export default function bindActionCreators(actionCreators, dispatch) {if (typeof actionCreators === 'function') {return bindActionCreator(actionCreators, dispatch)}if (typeof actionCreators !== 'object' || actionCreators === null) {throw new Error(`bindActionCreators expected an object or a function, instead received ${actionCreators === null ? 'null' : typeof actionCreators}. ` +`Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`)}const keys = Object.keys(actionCreators)const boundActionCreators = {}for (let i = 0; i < keys.length; i++) {const key = keys[i]const actionCreator = actionCreators[key]if (typeof actionCreator === 'function') {boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)}}return boundActionCreators
}
bindActionCreators.js 里面有一个 bindActionCreator,bindActionCreators 方法,
bindActionCreators会根据传入的是函数还是对象,采取不同的处理方式,
入参是函数,返回函数; 传入对象,返回对象。
6. combineReducers源码解析
combineReducers:把recuder函数们,合并成一个新的reducer函数,dispatch的时候,挨个执行每个reducer
在 reducer 层级的任何一级都可以调用 combineReducers。并不是一定要在最外层。实际上,你可以把一些复杂的子 reducer 拆分成单独的孙子级 reducer,甚至更多层。
redux 思考以及源码解析相关推荐
- react redux 简化_Redux 源码解析
前言 近日,出于对 Redux 的好奇和想对自己用过的东西知根知底之目的,做了一个 Redux 的自我检测,以便彻底了解其精髓之处.下面我会对使用 Redux 之后产生的疑问做一个清单,用问题导向往下 ...
- Redux异步解决方案之Redux-Thunk原理及源码解析
前段时间,我们写了一篇Redux源码分析的文章,也分析了跟React连接的库React-Redux的源码实现.但是在Redux的生态中还有一个很重要的部分没有涉及到,那就是Redux的异步解决方案.本 ...
- Redux 源码解析系列(一) -- Redux的实现思想
文章来源: IMweb前端社区 黄qiong(imweb.io) IMweb团队正在招聘啦,简历发至jayccchen@tencent.com Redux 其实是用来帮我们管理状态的一个框架,它暴露给 ...
- webpack那些事:浅入深出-源码解析构建优化
基础知识回顾 入口(entry) module.exports = {entry: './path/to/my/entry/file.js' }; //或者 module.exports = {ent ...
- Flutter 路由源码解析
前言 这一次,我尝试以不贴一行源代码的方式向你介绍 Flutter 路由的实现原理,同时为了提高你阅读源码的积极性,除了原理介绍以外,又补充了两个新的模块:从源码中学习到的编程技巧,以及 阅读源码之后 ...
- React深入学习与源码解析笔记
***当前阶段的笔记 *** 「面向实习生阶段」https://www.aliyundrive.com/s/VTME123M4T9 提取码: 8s6v 点击链接保存,或者复制本段内容,打开「阿里云盘」 ...
- Colly源码解析——结合例子分析底层实现
通过<Colly源码解析--框架>分析,我们可以知道Colly执行的主要流程.本文将结合http://go-colly.org上的例子分析一些高级设置的底层实现.(转载请指明出于break ...
- 死磕 java同步系列之ReentrantReadWriteLock源码解析
问题 (1)读写锁是什么? (2)读写锁具有哪些特性? (3)ReentrantReadWriteLock是怎么实现读写锁的? (4)如何使用ReentrantReadWriteLock实现高效安全的 ...
- kube-proxy源码解析
kube-proxy源码解析 ipvs相对于iptables模式具备较高的性能与稳定性, 本文讲以此模式的源 码解析为主,如果想去了解iptables模式的原理,可以去参考其实现,架构上无差别. ku ...
最新文章
- 一路慢行的JavaScript之旅(add)!!!
- 用Unity开发一款塔防游戏(一):攻击方设计
- 04.elasticsearch-dynamic_mapping_and_index_template
- python网络编程-socket编程
- java 性能调优_Java性能调优调查结果(第四部分)
- python土味情话_土味情话表情包下载
- python 对xlsx文件数根据日期进行统计分析_Python处理Excel的常用操作(一)
- 微信小程序时代,哪些人能赚到第一桶金
- Linux Shell脚本入门教程系列之(一)Shell简介
- idea--Project Structure
- 年入10亿,“山寨”耳机芯片凶猛
- MATLAB数值计算笔记
- 基于Monorail的系统功能模块化
- 考前必练15道题_《系统集成项目管理工程师备考宝典》
- java 优酷视频缩略图_通过正则表达式获取优酷视频缩略图
- 基于人工智能的搜索引擎优化软件-市场现状及未来发展趋势
- 《NVM-Express-1_4-2019.06.10-Ratified》学习笔记(8.8)-- Reservations
- NX二次开发-UFUN工程图导入视图UF_DRAW_import_view
- OpenStack裸金属使用总结
- RFID技术如何解决鞋帽行业应用