美文网首页
05从源码角度看combineReducers

05从源码角度看combineReducers

作者: zdxhxh | 来源:发表于2019-12-26 10:48 被阅读0次

为什么需要多个reducer

如果只有一个reducer,就代表状态管理树的状态只有一个对象,即state.

但是一个应用就像一本书,每一页都应该有自己的数据,所以仅仅有一个state是不足的,代码形式上也不够优雅

const initialState = { 
  myList : [
    '你他妈是不是脑袋有泡',
    '你他妈是不是脑袋有泡',
    '你他妈是不是脑袋有泡'
  ]
}

const reducer = (state = initialState,action)=> { 
  switch(action.type) { 
    case myAction.CAONIMA : { 
      state.myList = state.myList.map(item=>(action.payload))
      return state
    }
    default : { 
      return state
    }
  }
}

单一reducer,每次dispatch action后,都会更新currentState 然后通知所有订阅接口

try { 
  isDispatching = true 
  // 使用reducer 处理传入的action
  currentState = currentReducer(currentState,action)
} finally { 
  isDispatching = false 
}
currentListeners = nextListeners
const listeners = currentListeners
let index = -1 
// 遍历订阅的接口
while(++index<listeners.length) { 
  const listener = listeners[index]
  listener()
}

谈谈combineReducers

combineReducers接受一个字典,键为reducers的名字,值为reducer本身.

最后闭包缓存了这些reducers,最终并返回一个新的reducer函数

combineReducers({
  reducer1,
  reducer2
})

引入之后,state初始化就应该是这种形式

state = {
  reducer1 : reducer1(),
  reducer2 : reducer2()
}

事实上,他内部也是如此

return function combination(state = {}, action) { 
  // finalReducers为传入的reducers对象
  const finalReducerKeys = Object.keys(finalReducers)
  // 下一次执行reducer 存放结果的集合
  const nextState = {} 
  // 遍历 这意味着派发的action会触发所有的reducers 
  for(let i=0;i < finalReducerKeys.length;i++) { 
    const key = finalReducerKeys[i]
    const reducer = finalReducers[key]
    // 缓存上一次的reducer状态
    const previousStateForKey = state[key]
    // 触发reducer获取状态
    const nextStateForKey = reducer(previousStateForKey,action)
    if(typeof nextStateForKey === 'undefined') { 
      throw new Error(`key为${key}的reducer在处理${action.type}时 返回了一个空的state`)
    }
    nextState[key] = nextStateForKey
    // 如果这个reducer返回的state的地址与原有state的地址不一样 则赋值给hasChanged
    hasChanged = hasChanged || nextStateForKey !== previousStateForKey
  }
  // 如果有一个reducer的state地址变了,则返回新的nextState,否则返回state
  return hasChanged ? nextState : state
}

实战演习

const initState1 = { 
  meta : '树1'
}
const initState2 = { 
  meta : '树2'
}

const reducer1 = (state=initState1,action)=> {
  switch(action.type) { 
    default : return state 
  }
}

const reducer2 = (state=initState2,action)=> {
  switch(action.type) { 
    case 'AAAAAA' : { 
      state.meta = action.payload
      return state
    }
    default : return state 
  }
}

export default createStore(combineReducers({
  reducer1 : reducer1,
  reducer2 : reducer2,
}))

在某个组件中

onClickHandler() { 
  store.dispatch({
    type : 'AAAAAA',
    payload : "我妈妈在看直播 你们别骂了"
  })
}

点击之后派发action,就会更新state,虽然没有改变state的地址,但还是会触发所有订阅store的接口,通知state发生了改变

image.png

相关文章

网友评论

      本文标题:05从源码角度看combineReducers

      本文链接:https://www.haomeiwen.com/subject/fsskoctx.html