这一小节我们来处理下 reducer 的问题。啥问题?
我们知道 reducer 是一个计划函数,接收老的 state,按计划返回新的 state。那我们项目中,有大量的 state,每个 state 都需要计划函数,如果全部写在一起会是啥样子呢?
所有的计划写在一个 reducer 函数里面,会导致 reducer 函数及其庞大复杂。按经验来说,我们肯定会按组件维度来拆分出很多个 reducer 函数,然后通过一个函数来把他们合并起来。
我们来管理两个 state,一个 counter,一个 info。
let state = {counter: {count: 0},info: {name: '前端九部',description: '我们都是前端爱好者!'}}
他们各自的 reducer
/*counterReducer, 一个子reducer*//*注意:counterReducer 接收的 state 是 state.counter*/function counterReducer(state, action) {switch (action.type) {case 'INCREMENT':return {count: state.count + 1}case 'DECREMENT':return {...state,count: state.count - 1}default:return state;}}
/*InfoReducer,一个子reducer*//*注意:InfoReducer 接收的 state 是 state.info*/function InfoReducer(state, action) {switch (action.type) {case 'SET_NAME':return {...state,name: action.name}case 'SET_DESCRIPTION':return {...state,description: action.description}default:return state;}}
那我们用 combineReducers 函数来把多个 reducer 函数合并成一个 reducer 函数。大概这样用
const reducer = combineReducers({counter: counterReducer,info: InfoReducer});
我们尝试实现下 combineReducers 函数
function combineReducers(reducers) {/* reducerKeys = ['counter', 'info']*/const reducerKeys = Object.keys(reducers)/*返回合并后的新的reducer函数*/return function combination(state = {}, action) {/*生成的新的state*/const nextState = {}/*遍历执行所有的reducers,整合成为一个新的state*/for (let i = 0; i < reducerKeys.length; i++) {const key = reducerKeys[i]const reducer = reducers[key]/*之前的 key 的 state*/const previousStateForKey = state[key]/*执行 分 reducer,获得新的state*/const nextStateForKey = reducer(previousStateForKey, action)nextState[key] = nextStateForKey}return nextState;}}
我们来尝试下 combineReducers 的威力吧
const reducer = combineReducers({counter: counterReducer,info: InfoReducer});let initState = {counter: {count: 0},info: {name: '前端九部',description: '我们都是前端爱好者!'}}let store = createStore(reducer, initState);store.subscribe(() => {let state = store.getState();console.log(state.counter.count, state.info.name, state.info.description);});/*自增*/store.dispatch({type: 'INCREMENT'});/*修改 name*/store.dispatch({type: 'SET_NAME',name: '前端九部2号'});
本小节完整源码见 demo-3
