Redux源码分析(createStore)

使用redux都快3年了,到现在也没认真去了解一下源码罪过啊,所以需要对它进行一些分析和学习,一方面能更好的去使用它,另一方面也学习一下该框架的设计思路,首先我们看到 redux/src/index.js 文件

export {createStore,combineReducers,bindActionCreators,applyMiddleware,compose,__DO_NOT_USE__ActionTypes
}
复制代码

所以主要部分也就是上面几个函数,我们下面一点点去分析每一个功能点


createStore

其实该文件有着大量的注释了,大家可以先简单的看看代码中的注释了解一遍。 其实createStore就是返回了一个对象,这个对象只有几个方法而已,而我们常用的就是dispatchsubscribegetState这三个了

 * Creates a Redux store that holds the state tree.* The only way to change the data in the store is to call `dispatch()` on it.
复制代码

该函数的作用呢就是建立一个store(废话嘛),那么什么是store呢?我的理解 就是一个仓库,存着整个程序的状态,且只能有一个,就是用这一个store搞定项目中的全部状态,当然不论多大的项目,统统只有这一个,弄两个肯定不好使,并且只有一个路子去修改里面的数据,那么就是调用dispatch()

 function createStore(reducer, preloadedState, enhancer)
复制代码

可以看到函数体主要三个参数,简单说下

  • reducer:它是一个函数可以表达为:(preState,action) => newState就是说根据action和之前的状态,返回一个的状态(这里的新是新构建,而不是修改过,这点切记)
  • preloadedState:字面理解即可,预先加载的状态,即初始状态
  • enhancer:这个需要拿出篇幅来说了,增强剂,增强createStore
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {enhancer = preloadedStatepreloadedState = undefined}
复制代码

也容易理解,在只有两个参数的情况,并且第二个为funcion的时候,那么第二个参数就是enhancer了,交互一下参数位置

  if (typeof enhancer !== 'undefined') {if (typeof enhancer !== 'function') {throw new Error('Expected the enhancer to be a function.')}return enhancer(createStore)(reducer, preloadedState)}
复制代码

对enchancer类型判断,可以看到enhancer就是将store传入,在内部处理之后再将store返回来,继续传入reducer和初始状态进行构建

  let currentReducer = reducerlet currentState = preloadedStatelet currentListeners = []let nextListeners = currentListenerslet isDispatching = falsefunction ensureCanMutateNextListeners() {if (nextListeners === currentListeners) {nextListeners = currentListeners.slice()}}
复制代码

建立一些变量保存reducer,state,以及订阅器保存在nextListeners中,ensureCanMutateNextListeners相当于每次对当前的订阅器进行备份,因为每次订阅一个listener的时候都是对nextListeners数组进行添加

function subscribe(listener) {if (typeof listener !== 'function') {throw new Error('Expected the listener to be a function.')}if (isDispatching) {throw new Error('You may not call store.subscribe() while the reducer is executing. ' +'If you would like to be notified after the store has been updated, subscribe from a ' +'component and invoke store.getState() in the callback to access the latest state. ' +'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.')}let isSubscribed = trueensureCanMutateNextListeners()nextListeners.push(listener)return function unsubscribe() {if (!isSubscribed) {return}if (isDispatching) {throw new Error('You may not unsubscribe from a store listener while the reducer is executing. ' +'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.')}isSubscribed = falseensureCanMutateNextListeners()const index = nextListeners.indexOf(listener)nextListeners.splice(index, 1)}}
复制代码

订阅器,注册监听函数,每一个listener都是一个func,并且返回了一个取消注册监听的函数unScribe,用于删除listener,其实就是将一个个的函数添加到数组中,之后每次在store发生变化的时候(其实也就是调用dispatch的时候)就会触发它~

  function dispatch(action) {if (!isPlainObject(action)) {throw new Error('Actions must be plain objects. ' +'Use custom middleware for async actions.')}if (typeof action.type === 'undefined') {throw new Error('Actions may not have an undefined "type" property. ' +'Have you misspelled a constant?')}if (isDispatching) {throw new Error('Reducers may not dispatch actions.')}try {isDispatching = truecurrentState = currentReducer(currentState, action)} finally {isDispatching = false}const listeners = (currentListeners = nextListeners)for (let i = 0; i < listeners.length; i++) {const listener = listeners[i]listener()}return action}
复制代码

上面呢就是这里比较重要的dispatch函数了,其实非常简单,主要就是它:

 currentState = currentReducer(currentState, action)
复制代码

将当前的全部状态和action传入reducer,得到新的state,这样就完成了state的状态更新了,之后再去遍历全部的listeners,从而在各个listeners的内部去更新view,完成整个流程(返回值其实还是这个action对象),其实以上内容和三个函数应该是redux的核心内容了,下面用一种简单的总结来表达一下store(借鉴的阮一峰的)

const createStore = (reducer) => {let state;let listeners = [];const getState = () => state;const dispatch = (action) => {state = reducer(state, action);listeners.forEach(listener => listener());};const subscribe = (listener) => {listeners.push(listener);return () => {listeners = listeners.filter(l => l !== listener);}};dispatch({});return { getState, dispatch, subscribe };
};
复制代码

而该文件还有两个函数分别是

function replaceReducer(nextReducer)
function observable()
复制代码

第一个很明显替换整个reducer用,在一些热加载场景应该会用到 而第二个暂时还不太理解作者意图,用观察者替换订阅发布吗?暂时先不去想 以上就是整个createStore的源码分析~

更多内容与讨论可以参考我的github.com/jinjiaxing/…

转载于:https://juejin.im/post/5cb946e4f265da038c020f2f

Redux源码分析(一)相关推荐

  1. redux源码分析之一:createStore.js

    欢迎关注redux源码分析系列文章: redux源码分析之一:createStore.js redux源码分析之二:combineReducers.js redux源码分析之三:bindActionC ...

  2. redux源码分析之二:combineReducers.js

    欢迎关注redux源码分析系列文章: redux源码分析之一:createStore.js redux源码分析之二:combineReducers.js redux源码分析之三:bindActionC ...

  3. Redux源码分析--Enhancer

    Redux源码分析: Redux源码分析--Middleware(1) Redux源码分析--Middleware(2) Redux源码分析--Enhancer Redux源码分析--createSt ...

  4. redux middleware 源码分析

    原文链接 middleware 的由来 在业务中需要打印每一个 action 信息来调试,又或者希望 dispatch 或 reducer 拥有异步请求的功能.面对这些场景时,一个个修改 dispat ...

  5. koa源码分析-co模块以及thunk

    Thunk以及CO模块 co4.0之前都是返回的thunk函数 之后的都是返回promise thunk thunk:在 JavaScript 语言中,Thunk 函数替换的是将多参数函数,替换成单参 ...

  6. Vuex 2.0 源码分析

    作者:滴滴公共前端团队 - 黄轶 大家好,我叫黄轶,来自滴滴公共前端团队,我们团队最近写了一本书 --<Vue.js 权威指南>,内容丰富,由浅入深.不过有一些同学反馈说缺少 Vuex 的 ...

  7. 学习 redux 源码整体架构,深入理解 redux 及其中间件原理

    如果觉得内容不错,可以设为星标置顶我的公众号 1. 前言 你好,我是若川.这是学习源码整体架构系列第八篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是 ...

  8. 【源码分析】redux-thunk

    前言 前面学习redux时,学到了applyMiddleware云里雾里,所以这次学习一下redux-thunk的源码,希望有助于深入理解applyMiddleware的源码实现. redux-thu ...

  9. react-redux源码分析及实现原型(下)

    上一次我们讲解了Provider.connect.selectorFactory.这次主要分析 connectAdvanced 这个核心API. react-redux源码分析及实现原型_上 conn ...

最新文章

  1. 张一鸣宣布卸任字节CEO!网友:完不成OKR被优化了!
  2. 常用的异常检测算法有哪些?
  3. oracle查询一个字符串所在表
  4. 深入理解定位父级offsetParent及偏移大小
  5. vue中怎么清空tab选项卡的缓存_vue Tab切换以及缓存页面处理的几种方式
  6. jdk官网历史版本下载Oracle账号密码
  7. STM32 电机教程 8 - 步进电机开环电流控制
  8. Linux下命令行安装weblogic10.3.6
  9. WebTable之ChildItem方法应用
  10. Perform the Combo CodeForces - 1311C(字符串反转+树状数组)
  11. 线程并发库和线程池的作用_线程和并发介绍
  12. as_hash ruby_Ruby中带有示例的Hash.each_pair方法
  13. 1.5 编程基础之循环控制 09 奇数求和
  14. PHP内核通用网站后台权限管理系统源码
  15. HBuilderX是什么
  16. jquery的validate表单验证表单注册插件
  17. [转]word 转换成pdf
  18. 如何设置Idea字体颜色
  19. php云erp进销存v8手机端,PHP仿金蝶云ERP进销存V8网络多仓版源码
  20. 证券机构分析师研报靠谱么?关于波司登沽空与买入报告

热门文章

  1. 苹果广告背景音乐大全【转】
  2. 红杉资源出售麦考林29%股份套现1亿美元
  3. 总结:Sharepoint2010 Client Object Model -- Silverlight Client
  4. Effective C# Item45 : 优先选择强异常安全保证
  5. bq4050读固件_stm32f767 实现模拟SMBUS驱动bq4050
  6. Java Web 程序设计----基于SSM框架(正在更新中)
  7. 安装 | cmd(命令提示符)窗口下使用conda安装TensorFlow
  8. C++练习 | C++中Vector的使用
  9. python如何判断字符串是否包含某些汉字_Python如何判断一个字符串是否包含指定子字符串...
  10. 易语言单窗口单ip软件源码_好人多窗口同步器:多台电脑同步视频演示