redux原则之一就是单一性,即状态,仓库,reducer都是唯一的,但在组件式的技术开发中,为了好管理状态,通常一个组件,或嵌套组件对应一个 reducer, 最后再合并成一个大的reducer
代码太多,请参考演示代码
代码演示两个组件的都有各自的组件状态,怎么进行合并
可能有不明白,左边这个index.js
这个文件的 count1Reducer
和count2Reducer
的第一个参数为啥是那样写的
解释一下:
看右边的
count1Reducer()
函数,第一个参数是state, 默认值是 initState 的对象, 左边调用的时候, 第一次传入就是state.count1
是没有值的 , 所以调用这一次,传入的参数是undefined,则用默认值,接着走判断, 都不满足,走最后的default
,先拿到默认值, 后边再传入的时候就有值了, 不要被搞晕了
- 为了解决上述问题,官方提供了一个
combineReducers(reducers)
的Api, 用于帮你合并多个小的reducer - 调用此方法,传入一个对象
import { combineReducers } from 'redux';
export default combineReducers({
count1,
count2,
...
});
实现 combineReducers()
方法
- 代码不好理解,先屡屡
- 自己写合并时, 依旧需要传入state, action,最后导出一个对象, 对象的key 对应的是 你的
reducer
函数
import { count1Reducer } from './count1';
import { count2Reducer } from './count2';
function (state = {}, action) {
let finalState = {};
finalState.count1 = count1Reducer(state.count1, action);
finalState.count2 = count2Reducer(state.count2, action);
return finalState;
}
- 再看
combineReducers
函数, 接收一个对象类型的参数,所以组合以上两步,先返回一个函数,在这个函数里进行处理合并
// reducers参数 是一个对象
function combineReducers(reducers){}
- 合并1 和 2 的代码, 最后导出一个对象
// reducers参数 是一个对象
function combineReducers(reducers){
return function (state = {}, action) {
const nextState = {};
// ...处理 逻辑
return nextState;
};
}
- 处理上边的逻辑部分
- 1: 先把传入的对象的每个key组合成一个数组
- 2:循环这个数组
- 实现以上两步
export default function combineReducers(reducers) {
// 拿到每个key,组成数组
const reducerKeys = Object.keys(reducers);
return function (state = {}, action) {
const nextState = {};
// 循环
for (let i = 0; i < reducerKeys; i++) {
// 拿到每一个数组的每一项
const key = reducerKeys[i]
// 拿到每个reducer函数的状态数据
const reducerState = state[key]
// 获取每个key对象的小的reducer函数
const reducer = reducers[key];
// 给 nextState对象赋值,key 是传入的key, 值为每个reducer函数执行的结果
nextState[key] = reducer(reducerState, action);
}
return nextState;
};
}
- 使用函数式编程循环, 简化代码量,
function combineReducers(reducers) {
const reducerKeys = Object.keys(reducers);
return function (state = {}, action) {
const nextState = {};
reducerKeys.forEach(
(reducerKey) =>
(nextState[reducerKey] = reducers[reducerKey](
state[reducerKey],
action,
)),
);
return nextState;
};
}
另外,仓库里做了个 优化, 它判断了一下,本次传入的状态和上一次相比有木有变化, 如果没有,就还拿老值,否则才会用新的值