最近在读Redux源码,现将自己实现的代码和理解贴上,后期再补充详细~
由于在大中型项目中,操作比较复杂,数据结构也比较复杂,因此,需要对reducer进行细分。redux提供了方法,可以帮助我们更加方便的合并reducer,combineReducers会合并reducer,得到一个新的reducer,该新的reducer管理一个对象,该对象中的每一个属性交给对应的reducer管理。
代码很简单,组装reducers,返回一个reducer,数据使用一个对象表示,对象的属性名与传递的参数对象保持一致,主要是需要对传入的reducer进行检验:
import isPlainObject from "./utils/isPlainObject";
import ActionTypes from "./utils/ActionTypes";
function validateReducers(reducers) {
if (typeof reducers !== "object") {
throw new TypeError("reducers must be an object");
}
if (!isPlainObject(reducers)) {
throw new TypeError("reducers must be a plain object");
}
//验证reducer的返回结果是不是undefined
for (const key in reducers) {
if (reducers.hasOwnProperty(key)) {
const reducer = reducers[key];//拿到reducer
//传递一个特殊的type值
let state = reducer(undefined, {
type: ActionTypes.INIT()
})
// null不绝对等于undefined
if (state === undefined) {
throw new TypeError("reducers must not return undefined");
}
// 再次判断是否返回undefined
state = reducer(undefined, {
type: ActionTypes.UNKNOWN()
})
if (state === undefined) {
throw new TypeError("reducers must not return undefined");
}
}
}
}
export function combineReducers(reducers) {
validateReducers(reducers);
/**
* 返回的是一个reducer函数
*/
return function (state = {}, action) {
const newState = {}; //要返回的新的状态
for (const key in reducers) {
if (reducers.hasOwnProperty(key)) {
const reducer = reducers[key];
newState[key] = reducer( state[key], action);
}
}
return newState; //返回状态
}
}
plain-object(平面对象),它的__proto__指向Object.prototype
/**
* 判断某个对象是否是一个plain-object
* @param {*} obj
*/
export default function isPlainObject(obj) {
if (typeof obj !== "object") {
return false;
}
return Object.getPrototypeOf(obj) === Object.prototype;
初始化时调用的action,这里要对传入的reducers做验证,首先是触发INIT类型的action,如果这里返回undefined表示reducer未做默认处理;然后是触发PROBE_UNKNOWN_ACTION类型的aciton,如果这里返回undefined表示reducer占用了init的命名空间
/**
* 得到一个指定长度的随机字符串
* @param {*} length
*/
function getRandomString(length) {
return Math.random().toString(36).substr(2, length).split("").join(".")
}
export default {
INIT() {
return `@@redux/INIT${getRandomString(6)}`
},
UNKNOWN(){
return `@@redux/PROBE_UNKNOWN_ACTION${getRandomString(6)}`
}
}