目录
1,分析
大型项目中,数据和操作都比较复杂,所以会对 reducer
进行细分管理。
combineReducers
的作用:结合多个 reducer
。
举例:
js
// reducer.js
import { combineReducers } from "redux";
import loginReducer from "./login";
import userReducer from "./user";
export default combineReducers({
a: loginReducer,
b: userReducer,
});
js
// 使用
import { createStore } from "redux";
import reducer from "./reducer";
const store = createStore(reducer);
2,实现
2.1,简单实现
js
// reducer.js
import loginReducer from "./login";
import userReducer from "./user";
export default (state = {}, action) => {
const newState = {
a: loginReducer(state.a, action),
b: userReducer(state.b, action),
};
return newState;
};
解释 :
createStore(reducer)
初始化时,会调用一次 reducer
,此时 state.a = undefined
,所以会使用 loginReducer(state = {})
的默认值进行初始化,并将返回值作为 newState.a
的初始值保存。
之后分发指定 action
时,state.a
就是旧值{}
,作为 loginReducer
的 state
传入。
2.2,参考源码具体实现
在使用官方的 combineReducers
时,发现了2个特点:
- 所有细分的
reducer
的state
参数必须指定初始值 ,如果不想指定,需要默认为null
,而不是undefined
(相当于没有指定初始值)。 - 所有细分的
reducer
中,不能使用特殊的type
来判断做一些事情。
举例1 :没有初始值,得指定为 null
。
js
// reducer/xxx.js
export default (state = null, { type, payload }) => {
switch (type) {
case LOGIN:
return payload;
default:
return state;
}
};
举例2 :特殊的 type
,比如 createStore()
初始化时的 type=@@redux/INITw.2.n.b.2.o
;还有 combineReducers()
初始化时的 type=@@redux/PROBE_UNKNOWN_ACTIONe.a.v.4.3.3
。
不能在某个 reducer
中使用这2个特殊 type
,会报错。
js
// reducer/xxx.js
export default (state = null, { type, payload }) => {
switch (type) {
case type.startsWith("@@redux/INIT"):
console.log("craeteStore 初始化");
case type.startsWith("@@redux/PROBE_UNKNOWN_ACTION"):
console.log("combineReducers 初始化");
default:
return state;
}
};
实现
js
export const combineReducers = (reducers) => {
validate(reducers);
return (state = {}, action) => {
let newState = {};
for (const key in reducers) {
if (Object.hasOwnProperty.call(reducers, key)) {
const reducer = reducers[key];
// 参考上面的简单实现。
newState[key] = reducer(state[key], action);
}
}
return newState;
};
};
function validate(reducers) {
if (typeof reducers !== "object" || Object.getPrototypeOf(reducers) !== Object.prototype) {
throw new Error("reducers 必须是一个 plain Object");
}
for (const key in reducers) {
if (Object.hasOwnProperty.call(reducers, key)) {
const reducer = reducers[key];
// 判断是否进行了初始化,和是否使用了特殊 type
let state = reducer(undefined, { type: `@@redux/INIT${getRandomString()}` });
if (state === undefined) {
throw new TypeError("reducers must not return undefined");
}
state = reducer(undefined, { type: `@@redux/PROBE_UNKNOWN_ACTION${getRandomString()}` });
if (state === undefined) {
throw new TypeError("reducers must not return undefined");
}
}
}
}
function getRandomString() {
return Math.random().toString(36).substring(2, 8).split("").join(".");
}
以上。