实现 combineReducers
上一篇,我已经指出我们的 redux 只能管理单个 count
状态,虽然我们把 count
改造成一个 Object
,所有状态都放在这个 Object
里,这样子的代码也难以维护和阅读。
所以 Redux
为我们提供了 combineReducers
,让我们能拆分 Reducer
。
官网中提到过:一个 Redux 应用中应当只有一个 store
。那么这种方式是否违反这个原则呢?我们去实现一遍便能知道答案了。
我们先把代码从自己的 mini-redux 切换到官方库,并加入 combineReducers
。
// import {applyMiddleware, createStore} from "../mini-redux";
import {applyMiddleware, createStore, combineReducers} from "redux";
// import thunk from "redux-thunk";
// import logger from "redux-logger";
import myLogger from "../mini-redux/my-logger.js";
import myThunk from "../mini-redux/my-thunk.js";
function counterReducer(state = 0, action) {
switch (action.type) {
case "ADD":
return state + 1;
case "MINUS":
return state - 1;
default:
return state;
}
}
export const store = createStore(combineReducers({
count: counterReducer,
}), applyMiddleware(myThunk, myLogger));
我们的应用应当仍然可以运行,我们可以通过我们的日志中间件查看到派发 action 后的日志,我们的状态从单个值 0 变成了 {count: 0}
, 这就意味着全局 state 上可以挂载更多地状态了。
而且,这个 count
的键名是我们调用 combineReducers
时指定的。
export default function combineReducers(reducers) {
return function (state = {}, action) {
const nextState = {};
let hasChanged = false;
for (let key in reducers) {
nextState[key] = reducers[key](state[key], action);
hasChanged = hasChanged || nextState[key] !== state[key];
}
hasChanged = hasChanged || Object.keys(nextState).length !== Object.keys(state).length;
return hasChanged ? nextState : state;
};
}
export { default as createStore } from "./createStore.js";
export { default as applyMiddleware } from "./applyMiddleware.js";
export { default as combineReducers } from "./combineReducers.js";
import {applyMiddleware, createStore, combineReducers} from "../mini-redux";
// import {applyMiddleware, createStore, combineReducers} from "redux";
// import thunk from "redux-thunk";
// import logger from "redux-logger";
import myLogger from "../mini-redux/my-logger.js";
import myThunk from "../mini-redux/my-thunk.js";
function counterReducer(state = 0, action) {
switch (action.type) {
case "ADD":
return state + 1;
case "MINUS":
return state - 1;
default:
return state;
}
}
export const store = createStore(combineReducers({
count: counterReducer,
}), applyMiddleware(myThunk, myLogger));
可以看出,combineReducers
的作用就是合成一个大的 reducer 函数。
这个大的 reducer 需要通过 key
找到对子 reducer
和其状态并进行变更。
这里有个 hasChanged
变量,是一个优化手段,有时候状态不一定会发生变更,但是如果我们这个 nextState 每次执行将是一个新对象,有了这个机制,react
端才有可能做优化,我们这里由于订阅后有 forceUpdate
,还无法做到这个优化。
到这里,我们也就知道了,combineReducers
并不违反单一 store 的原则,实际上它们仍然是同一个 store。
手写 mini-redux 到这里就告一段落了,后面我们还会实现自己的 React-redux 库。