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 思考以及源码解析相关推荐

  1. react redux 简化_Redux 源码解析

    前言 近日,出于对 Redux 的好奇和想对自己用过的东西知根知底之目的,做了一个 Redux 的自我检测,以便彻底了解其精髓之处.下面我会对使用 Redux 之后产生的疑问做一个清单,用问题导向往下 ...

  2. Redux异步解决方案之Redux-Thunk原理及源码解析

    前段时间,我们写了一篇Redux源码分析的文章,也分析了跟React连接的库React-Redux的源码实现.但是在Redux的生态中还有一个很重要的部分没有涉及到,那就是Redux的异步解决方案.本 ...

  3. Redux 源码解析系列(一) -- Redux的实现思想

    文章来源: IMweb前端社区 黄qiong(imweb.io) IMweb团队正在招聘啦,简历发至jayccchen@tencent.com Redux 其实是用来帮我们管理状态的一个框架,它暴露给 ...

  4. webpack那些事:浅入深出-源码解析构建优化

    基础知识回顾 入口(entry) module.exports = {entry: './path/to/my/entry/file.js' }; //或者 module.exports = {ent ...

  5. Flutter 路由源码解析

    前言 这一次,我尝试以不贴一行源代码的方式向你介绍 Flutter 路由的实现原理,同时为了提高你阅读源码的积极性,除了原理介绍以外,又补充了两个新的模块:从源码中学习到的编程技巧,以及 阅读源码之后 ...

  6. React深入学习与源码解析笔记

    ***当前阶段的笔记 *** 「面向实习生阶段」https://www.aliyundrive.com/s/VTME123M4T9 提取码: 8s6v 点击链接保存,或者复制本段内容,打开「阿里云盘」 ...

  7. Colly源码解析——结合例子分析底层实现

    通过<Colly源码解析--框架>分析,我们可以知道Colly执行的主要流程.本文将结合http://go-colly.org上的例子分析一些高级设置的底层实现.(转载请指明出于break ...

  8. 死磕 java同步系列之ReentrantReadWriteLock源码解析

    问题 (1)读写锁是什么? (2)读写锁具有哪些特性? (3)ReentrantReadWriteLock是怎么实现读写锁的? (4)如何使用ReentrantReadWriteLock实现高效安全的 ...

  9. kube-proxy源码解析

    kube-proxy源码解析 ipvs相对于iptables模式具备较高的性能与稳定性, 本文讲以此模式的源 码解析为主,如果想去了解iptables模式的原理,可以去参考其实现,架构上无差别. ku ...

最新文章

  1. 一路慢行的JavaScript之旅(add)!!!
  2. 用Unity开发一款塔防游戏(一):攻击方设计
  3. 04.elasticsearch-dynamic_mapping_and_index_template
  4. python网络编程-socket编程
  5. java 性能调优_Java性能调优调查结果(第四部分)
  6. python土味情话_土味情话表情包下载
  7. python 对xlsx文件数根据日期进行统计分析_Python处理Excel的常用操作(一)
  8. 微信小程序时代,哪些人能赚到第一桶金
  9. Linux Shell脚本入门教程系列之(一)Shell简介
  10. idea--Project Structure
  11. 年入10亿,“山寨”耳机芯片凶猛
  12. MATLAB数值计算笔记
  13. 基于Monorail的系统功能模块化
  14. 考前必练15道题_《系统集成项目管理工程师备考宝典》
  15. java 优酷视频缩略图_通过正则表达式获取优酷视频缩略图
  16. 基于人工智能的搜索引擎优化软件-市场现状及未来发展趋势
  17. 《NVM-Express-1_4-2019.06.10-Ratified》学习笔记(8.8)-- Reservations
  18. NX二次开发-UFUN工程图导入视图UF_DRAW_import_view
  19. OpenStack裸金属使用总结
  20. RFID技术如何解决鞋帽行业应用

热门文章

  1. 设计模式--模板方法模式--Java实现-- java访问控制关键字用法
  2. vsftp 具体操作
  3. redis专题:使用redis实现分布式锁
  4. 坑爹的公交卡充值的流程
  5. 用计算机演银河系,专家首次用计算机模拟类银河星系 分辨率极高
  6. JVM类加载理解(线程上下文类加载器、Tomcat类加载器)
  7. 电脑突然卡主动不了了_必看!电脑运行卡或软件卡死无响应,怎么办?
  8. html弹性盒子自适应比例,CCS弹性盒子中间自适应怎么设置
  9. SpringBoot整合kafka实战之带回调的生产者
  10. 一张图展示一段js代码的一生,变量对象、作用域链、闭包、this