Redux源码分析之combineReducers

combineReducers

对于业务复杂的应用,我们通常使用combineReducers拆分不同的reducer给不同的模块去消费
如果不同的模块需要做状态共享,可以使用相同的reducer

使用

import {
    createStore,
    combineReducers
} from 'redux'
import header from './reducer/header'
import person from './reducer/person'
const allReducer = combineReducers({
    header,
    person,
})
export default createStore(allReducer)

合并之后,不同reducer产生的partial state在state中以combineReducers的属性名区分

const allReducers = combineReducers({countReducer,countReducer2})
const store = createStore(allReducers,applyMiddleware(thunk))

// 产生的state如下
state:{
    countReducer: {count: 0},
    countReducer2: {count2: 0}
}

源码分析

对于combineReducers, 在dispatch时redux做的处理是遍历reducers为每个reducer传入action执行。
由于state做浅比较可以很容易判断state有无更新,因此只要任意一个nextState的地址发生了改变,就认为本次状态产生了更新,从而返回nextState, 否则返回老的state
redux并不关心action和reducer之间的映射关系。如果两个reducer都处理了某个action type,那么调度一次action会使得两个reducer都产生新的状态,基于这一点可以做不同模块之间的状态共享

export default function combineReducers(reducers) {
  const reducerKeys = Object.keys(reducers)
  const finalReducers = {}
  // 将partial reducers 浅拷贝到finalReducer中
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i]
    if (typeof reducers[key] === 'function') {
      finalReducers[key] = reducers[key]
    }
  }
  const finalReducerKeys = Object.keys(finalReducers)


  return function combination(state = {}, action) {
    let hasChanged = false
    const nextState = {}
    // 遍历partial reducers,为每一个partial reducer执行本次action返回nextState,任意一个nextState有变化就返回nextState,否则返回旧的state。redux并不通过action识别是哪个reducer里面的,redux的识别策略是为每个reducer执行一次action,如果有变化,说明是new state, 如果没有,说明是prevState
    // 每次遍历完毕都会对nextState和prevState做浅比较,识别是不是发生了状态更新
    // 任意一个状态更新,redux都会返回nextState,否则返回当前的state
    for (let i = 0; i < finalReducerKeys.length; i++) {
      const key = finalReducerKeys[i]  
      const reducer = finalReducers[key]
      const previousStateForKey = state[key]
      const nextStateForKey = reducer(previousStateForKey, action)
      nextState[key] = nextStateForKey
      
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    hasChanged =
      hasChanged || finalReducerKeys.length !== Object.keys(state).length
    return hasChanged ? nextState : state
  }
}
posted @ 2022-07-04 11:24  IslandZzzz  阅读(89)  评论(0编辑  收藏  举报