以前,已经写过一篇redux源码解读(一),主要分析了 redux
的核心思想,并用100多行代码实现一个简单的 redux
。可是,那个实现还不具有合并 reducer
和添加 middleware
的功能。git
今天咱们一块儿来看看合并 reducer
(即 combineReducers
) 的原理和实现。github
在分析原理以前,先来看看combineReducers
的用法:redux
import { createStore, combineReducers } from 'redux'; const addScore = (state, action) => {}; const deleteScore = (state, action) => {}; const rootReducer = combineReducers({addStore, deleteScore}); const store = createStore(rootReducer);
从上面的例子能够看出,combineReducers
接收的参数类型是一个原生对象,其中这个对象的每一个键值都是一个 reducer
纯函数。另外,由于 combineReducer()
返回的结果能够传递给createStore
做为参数,能够推出它返回的结果也是一个 reducer
函数。函数
了解了 combineReducer
用法以后 ,那开始一步一步的用代码来实现其功能吧。prototype
首先,须要先声明 combineReducers
的参数,而后判断传进来的参数是否是原生对象类型( plain object
),若是不是,则抛出异常,若是是,则须要获取该对象的全部属性(key)并存放到变量 reducerKeys
里面,而后对这些key进行遍历,过滤掉那些不是函数的值,并将结果放到 finalReducerKeys
里面。代码以下:code
export default function combineReducers(reducers) { // 判断参数reducers是否为对象 if(Object.prototype.toString.call(reducer) !== '[object Object]') { throw new Error('combineReducers expected plain object params'); } const reducerKeys = Object.keys(reducers); let finalReducerKeys = []; // 过滤掉value不是Function类型的键名,而后将结果放到fianlReducerKeys里面 reducerKeys.forEach((key, i) => { if(typeof reducers[key] === 'function') { finalReducerKeys.push(key); } }); }
前面已经提到过了 combineReducers
返回的结果是一个纯函数。那这个返回的函数须要处理些什么逻辑呢?由于他合并了其余的 reducers
,因此须要遍历这些 reducer
并执行他们。而后,并对比一下执行 reducer
以后的数据有没有变化 ,若是有变化则返回新的 state
, 不然直接返回以前的 state
。代码以下:对象
export default function combineReducers(reducers) { // 省略和前面相同的部分 // 返回一个新的、通过组合的reducer函数 return function(state = {}, action) { let hasChanged = false; const nextState = {}; // 遍历finalReducerKeys,并调用对应的reducer。 finalReducerKeys.forEach((key, i) => { const stateForKey = state[key]; const nextStateForKey = reducers[key](stateForKey, action); nextState[key] = nextStateForKey; // 若是先后状态不同,则hasChanged设为true if(stateForKey !== nextStateForKey) { hasChanged = true; } }); // 若是有变化,则返回新的state,不然返回旧的 return hasChanged ? nextState : state; } }
OK,《redux
源码解读(二)》就写到这里,今天周五啦,祝你们周末愉快哈!若是对 combineReducer
还有不明白的地方,欢迎留言讨论哈。另外,可能有些地方我分析得不到位的,建议到个人github去下载代码本身再好好研究一下。重要的事情说三遍:代码在这里下载! 代码在这里下载! 代码在这里下载!blog