写React也有段时间了,一直也是用Redux管理数据流,最近正好有时间分析下源码,一方面但愿对Redux有一些理论上的认识;另外一方面也学习下框架编程的思惟方式。react
一、Redux经过全局惟一的store对象管理项目中的stategit
var store = createStore(reducer,initialState);
二、能够经过store注册listener,注册的listener会在store tree每次变动后执行github
store.subscribe(function () { console.log("state change"); });
一、store调用dispatch
,经过action把变动的信息传递给reducer编程
var action = { type: 'add'}; store.dispatch(action);
二、store根据action携带type
在reducer中查询变动具体要执行的方法,执行后返回新的stateredux
export default (state = initialState, action)=>{ switch (action.type) { case 'add': return { count:state.count + 1 } break; default: break; } }
三、reducer执行后返回的新状态会更新到store tree中,触发由store.subscribe()
注册的全部listener数组
主要方法:闭包
查看完整createStore
请戳这里
createStore
方法用来注册一个store,返回值为包含了若干方法的对象,方法体以下:app
export var ActionTypes = { INIT: '@@redux/INIT' } export default function createStore(){ function getState(){} function dispatch(){} function subscribe(){} function replaceReducer(){} dispatch({ type: ActionTypes.INIT }) return { dispatch, subscribe, getState, replaceReducer } }
下面逐个代码段分析功能
createStore
完整函数声明以下:框架
createStore( reducer:(state, action)=>nextState, preloadedState:any, enhancer:(store)=>nextStore )=>{ getState:()=>any, subscribe:(listener:()=>any)=>any, dispatch:(action:{type:""})=>{type:""}, replaceReducer:(nextReducer:(state, action)=>nextState)=>void }
能够看出整个函数是一个闭包结构。参数有三个,返回值公开出若干方法异步
固然,createStore
内部处理了其重载形式,即:能够不传preloadedState
createStore( reducer:(state, action)=>nextState, enhancer:(store)=>nextStore )
参数:
进入createSore
首先执行以下操做:
createStore(reducer,preloadedState,enhancer)
和createStore(reducer,enhancer)
重点分析下50行:
return enhancer(createStore)(reducer, preloadedState)
本语句执行了外部传入的enhancer,接收旧createStore
,返回一个新createStore
并执行,此过程造成一次递归;
那么递归何时中止呢?
能够看到,新createStore
执行时,仅有reducer和preloadedState两个参数,再次运行到45行时,不会进入if条件 故不会再造成第二次递归,此时递归中止;
理论上,createStore
仅被加强了一次,那若是但愿对其进行屡次加强该怎么办呢?
Redux提供了compose
和applyMiddleWare
方法,用来在Store上注册中间件,由此来实现屡次加强。
getState
方法比较简单,直接返回当前store tree状态
currentReducer
、currentState
声明当前reducer方法集合和store tree状态,初始值为外部传入的createStore
参数,currentListeners
和nextListeners
定义了存放store变化时要执行响应函数的数组集合Redux采用了观察者模式,store内部维护listener数组,用于存储全部经过store.subscrib
注册的listener,store.subscrib
返回unsubscrib
方法,用于注销当前listener;当store tree更新后,依次执行数组中的listener
具体代码以下:
dispatch
方法主要完成两件事:
一、根据action查询reducer中变动state的方法,更新store tree
二、变动store tree后,依次执行listener中全部响应函数
有个问题须要注意:
方法中使用了全局定义的isDispatching
用于给变动中的store tree加锁;即:只有当本次store tree变动完毕后,才容许执行下一次变动,避免store tree响应多个变动时,结果不一样步的问题;但事实上,这种写法也决定了,目前的store tree只能响应同步变动(异步变动须要经过添加中间件实现)
replaceReducer
用于替换操做store tree中state的方式
整个方法代码量很少,从外部接收新的reducer方法后,替换掉内部旧的ruducer。
须要注意一下199行的dispatch
方法,这一行主动触发了一次变动。因为每次dispatch
执行后,redux都会执行reducer或子reducer方法(若是使用了combineReducers
),因此这一行的做用就是在初始化store tree中全部的state节点。
以上就是整个createStore
方法的主要实现过程,其中dispatch
方法为控制整个store tree变动的核心方法。触发store tree变动的方式只有一个,就是dispatch
一个action
结合上面store tree变动的过程,咱们能够看到,真正致使变动的核心代码就是:
currentState = currentReducer(currentState, action)
试想,若整个项目只经过一个reducer方法维护整个store tree,随着项目功能和复杂度的增长,咱们须要维护的store tree层级也会愈来愈深,当咱们须要变动一个处于store tree底层的state,reducer中的变动逻辑会十分复杂且臃肿。
而combineReducers
存在的目的就是解决了整个store tree中state与reducer一对一设置的问题。咱们能够根据项目的须要,定义多个子reducer方法,每一个子reducer仅维护整个store tree中的一部分state, 经过combineReducers
将子reducer合并为一层。这样咱们就能够根据实际须要,将整个store tree拆分红更细小的部分,分开维护。
combineReducers
完整代码请戳这里
整个函数体结构以下:
combineReducers( reducers:Object )=> reducer( state:any, action:{type:""} )
参数reducers是一个Object对象,其中包含全部待合并的子reducer方法
返回值是合并后的reducer方法,在执行此方法时,会在已合并的全部子reducer中查询要执行的reducer,并执行,变动其对应的state片断。
下面逐个代码段分析具体实现:
以上这部分主要用于规范化存储子ruducer的reducers对象
finalReducers
对象中assertReducerSanity
方法校验全部子reducer的初始值和执行后结果是否为空,是则提示错误。以上这段代码为combineReducers
的核心代码,其返回一个function,用于查询真正要变动的state片断
finalReducers
,获取到当前key对应的子reducer和子state,执行reducer获得当前state片断更新后的状态,并更新到整个store tree中。previousStateForKey
时,值可能为undefined,那么接下来执行var nextStateForKey = reducer(previousStateForKey, action)
其实是依次为每一个子state片断进行初始化。nextStateForKey !== previousStateForKey
直接经过引用关系判断state是否变动。故必定要注意,定义reducer方法时,必定要遵循函数式编程,确保传入的state与返回的state不要存在引用关系,不然可能致使store tree中状态没法更新。至此,咱们能够看到combineReducers
方法,实际就是在每次要执行reducer时,经过action.type定义的类型进行查询,得到子reducer并执行。
经过以上分析,咱们须要注意两个问题:
一、子reducer遵循函数式编程,不要直接变动做为参数传入的state,变动state后,必定要返回一个新state对象,不要跟参数state创建引用关系(可使用Immutable处理state)
二、因为combineReducers
内部仅经过action.type做为查询当前要执行的子reducer的依据,会更新全部查询到的state片断,故不建议子reducer中,action.type的值出现重复,不然可能会误更新state。
本篇经过分析源码整理了Redux中Store对象的执行逻辑,重点分析了dispatch(action)后,store tree内部状态如何更新。 篇幅所限,没有分析如何在store上注册中间件,以及如何在store tree变动后,触发页面更新的过程,这些会在以后的博客中更新 第一次写源码分析还有不少不足,若有错误,欢迎指正。