We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
前面说到,当你的state树变得非常复杂,需要存储许多状态时,你可以编写多个Reducer函数,每个Reducer函数仅处理维护一部分state,这样就可以达到模块化管理state的效果。而createStore的入参reducer是一个函数,如何将多个reducer组合成一个reducer则需要使用到Redux的另一个API:combineReducers。
首先应用官方文档多个reducer的例子,可能是这样:
// reducer function todos(state = [], action) { switch (action.type) { case ADD_TODO: return [ ...state, { text: action.text, completed: false } ] case TOGGLE_TODO: return state.map((todo, index) => { if (index === action.index) { return Object.assign({}, todo, { completed: !todo.completed }) } return todo }) default: return state } } // reducer function visibilityFilter(state = SHOW_ALL, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return action.filter default: return state } }
通过 combineReducers 组合这两个Reducer的调用例子是这样:
const todoApp= combineReducers({todos,todoApp})
首先来看看方法的签名
function combineReducers(reducers)
参数如下:
返回一个合成后的超强Reducer函数,形如:
combination(state = {}, action){ //.... }
combineReducers 传入多个reducer,每个reducer负责处理states树的一部分,经过组合后返回一个reducer,可作为createStore的reducer参数传入。主要是为了划分state树的数据处理逻辑,当state树变得复杂时,就非常有用。
方法的开头,定义了两个常量:
// 参数reducers所有的key值 (每个键值都是一个reducer函数的名字) const reducerKeys = Object.keys(reducers) // 最终的reducers对象 const finalReducers = {}
接着遍历参数 reducers 的key值,对一个个reducer进行检查:
// 遍历所有的key for (let i = 0; i < reducerKeys.length; i++) { const key = reducerKeys[i] // 非生产环境下 检查 reducer 是否为 undefined if (process.env.NODE_ENV !== 'production') { if (typeof reducers[key] === 'undefined') { warning(`No reducer provided for key "${key}"`) } } // 检查 reducer 是否是函数 if (typeof reducers[key] === 'function') { // 合法 加入到最终的reducer对象 finalReducers[key] = reducers[key] } }
这里的检查,其实就是对传入参数的过滤,即过滤掉了Reducer不为函数类型的值,最终得到一个 finalReducers 对象。当然,检查并没有那么轻松,接下来对 finalReducers 进行了更深一步的检查:
// finalReducers 的key值 const finalReducerKeys = Object.keys(finalReducers) // 对reducer是否合法进行进一步验证 let shapeAssertionError try { // 将上面检查得到的 finalReducers 对象 再进行更严格的检查 assertReducerShape(finalReducers) } catch (e) { shapeAssertionError = e }
assertReducerShape函数具体代码如下:
function assertReducerShape(reducers) { // 遍历所有的reducer Object.keys(reducers).forEach(key => { const reducer = reducers[key] // 发起一个Redux 私有的action ,同时传入的 state 是 undefined // reducer需要返回初始state ,否则报错 const initialState = reducer(undefined, { type: ActionTypes.INIT }) if (typeof initialState === 'undefined') { throw new Error( `xxxx` ) } // 发出一个未知的action // reducer需要返回原有的state 否则报错 if ( typeof reducer(undefined, { type: ActionTypes.PROBE_UNKNOWN_ACTION() }) === 'undefined' ) { throw new Error( `xxx` ) } }) }
还是之前提到的对于Reducer函数的要求,Redux内部对reducer有严格的要求,这里就不再重复说明了。 方法的最后,返回了合成的reducer,我们来看看这个reducer是如何分发action和对state树执行数据处理逻辑的:
// 最终返回的 reducer(state,action) return function combination(state = {}, action) { let hasChanged = false // 状态树是否发生了变化 const nextState = {} // 状态树的下一次状态 /* * 每个子reducer都会管理状态树的一部分状态 * dispatch发起一个action后 会分发给所有的子reducer执行 * 有需要的子reducer进行数据处理 返回新的state * 不需要的返回原有的state */ for (let i = 0; i < finalReducerKeys.length; i++) { const key = finalReducerKeys[i] const reducer = finalReducers[key] // 当前reducer的state值 const previousStateForKey = state[key] // 调用reducer函数 执行数据处理逻辑 // 返回处理后的 state const nextStateForKey = reducer(previousStateForKey, action) // 检查返回的state是否合法 if (typeof nextStateForKey === 'undefined') { const errorMessage = getUndefinedStateErrorMessage(key, action) throw new Error(errorMessage) } nextState[key] = nextStateForKey // 子reducer是否对state树做了更新 hasChanged = hasChanged || nextStateForKey !== previousStateForKey } // 只要有一个reducer修改了状态树,就返回新的状态树 return hasChanged ? nextState : state }
现在看来,combineReducers 是划分state树的数据处理逻辑给多个reducer实现并不复杂,每个reducer负责state树的一部分,当 dispatch 发起了一个action后,combination 会将这个action分发给所有的子 reducer,不处理此action的reducer返回原有状态就可以,只有处理此 action 的 reducer 才会返回更新后的部分state。
我们需要注意到的是,子reducer维护的那一部分state在全局state树中的命名,默认就是reducer的函数名,如有以下两个 reducer:
function todos(state = [] , action){ } function visibilityFilter(state = SHOW_ALL, action) { }
则合成之后的state树是这样的:
{ todos : [], visibilityFilter: SHOW_ALL }
如果要修改命名,则在调用 combineReducers 时,应该这样:
const todoApp= combineReducers({ anotherName: todos, yetAnotherName: todoApp })
拆分Reducer的好处是显而易见的,使Redux便于维护,同时代码更加清晰,但编写许多重复的reducer代码就会变得多余枯燥了。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前面说到,当你的state树变得非常复杂,需要存储许多状态时,你可以编写多个Reducer函数,每个Reducer函数仅处理维护一部分state,这样就可以达到模块化管理state的效果。而createStore的入参reducer是一个函数,如何将多个reducer组合成一个reducer则需要使用到Redux的另一个API:combineReducers。
多个Reducer的例子
首先应用官方文档多个reducer的例子,可能是这样:
通过 combineReducers 组合这两个Reducer的调用例子是这样:
combineReducers
方法签名
首先来看看方法的签名
参数如下:
方法返回
返回一个合成后的超强Reducer函数,形如:
方法作用
combineReducers 传入多个reducer,每个reducer负责处理states树的一部分,经过组合后返回一个reducer,可作为createStore的reducer参数传入。主要是为了划分state树的数据处理逻辑,当state树变得复杂时,就非常有用。
方法解读
方法的开头,定义了两个常量:
接着遍历参数 reducers 的key值,对一个个reducer进行检查:
这里的检查,其实就是对传入参数的过滤,即过滤掉了Reducer不为函数类型的值,最终得到一个 finalReducers 对象。当然,检查并没有那么轻松,接下来对 finalReducers 进行了更深一步的检查:
assertReducerShape函数具体代码如下:
还是之前提到的对于Reducer函数的要求,Redux内部对reducer有严格的要求,这里就不再重复说明了。
方法的最后,返回了合成的reducer,我们来看看这个reducer是如何分发action和对state树执行数据处理逻辑的:
总结
现在看来,combineReducers 是划分state树的数据处理逻辑给多个reducer实现并不复杂,每个reducer负责state树的一部分,当 dispatch 发起了一个action后,combination 会将这个action分发给所有的子 reducer,不处理此action的reducer返回原有状态就可以,只有处理此 action 的 reducer 才会返回更新后的部分state。
我们需要注意到的是,子reducer维护的那一部分state在全局state树中的命名,默认就是reducer的函数名,如有以下两个 reducer:
则合成之后的state树是这样的:
如果要修改命名,则在调用 combineReducers 时,应该这样:
拆分Reducer的好处是显而易见的,使Redux便于维护,同时代码更加清晰,但编写许多重复的reducer代码就会变得多余枯燥了。
The text was updated successfully, but these errors were encountered: