美文网首页
combineReducers原理

combineReducers原理

作者: 落花的季节 | 来源:发表于2017-05-26 14:53 被阅读242次

简介

随着应用变得复杂,需要对 reducer 函数 进行拆分,拆分后的每一块独立负责管理 state 的一部分。
Redux 中的 combineReducers 能让我们很方便地把多个 reducers 组合起来,成为一个新的 reducer。

原理

combineReducers辅助函数的作用是,把一个由多个不同 reducer 函作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore

合并后的 reducer 可以调用各个子 reducer,并把它们的结果合并成一个 state 对象。state 对象的结构由传入的多个 reducer 的 key 决定

state的最终结构为:

{
  reducer1: ...,
  reducer2: ...
}

通过上述的讲解我们可以知道,combineReducecrs的基本型态应该是这样的:

function combineReducers(reducers) {
  return function (state, action) { /*...*/ };
}

它接受 reducers 作为参数,然后返回一个标准的 reducer 函数。

下面我们就来看一下combineReducers的源码解析:

import { ActionTypes } from './createStore'
import isPlainObject from 'lodash/isPlainObject'
import warning from './utils/warning'

//根据key和action生成错误信息
function getUndefinedStateErrorMessage(key, action) {
  //...
}

//一些警告级别的错误
function getUnexpectedStateShapeWarningMessage(inputState, reducers, action, unexpectedKeyCache) {
  const reducerKeys = Object.keys(reducers)
  const argumentName = action && action.type === ActionTypes.INIT ?
    'preloadedState argument passed to createStore' :
    'previous state received by the reducer'

  //判断reducers是否为空数组
  //判断state是否是对象
  //给state中存在而reducer中不存在的属性添加缓存标识并警告
  //...
}


//这个方法用于检测用于组合的reducer是否是符合redux规定的reducer
function assertReducerSanity(reducers) {
  Object.keys(reducers).forEach(key => {
    const reducer = reducers[key]
    //调用reducer方法,undefined为第一个参数
    //使用前面说到过的ActionTypes.INIT和一个随机type生成action作为第二个参数
    //若返回的初始state为undefined,则这是一个不符合规定的reducer方法,抛出异常
    //...
  })
}

export default function combineReducers(reducers) {
  const reducerKeys = Object.keys(reducers) //所有的键名
  const finalReducers = {}
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i]

    if (process.env.NODE_ENV !== 'production') {
      if (typeof reducers[key] === 'undefined') {
        warning(`No reducer provided for key "${key}"`)
      }
    }

    //finalReducers是过滤后的reducers,它的每一个属性都是一个function
    if (typeof reducers[key] === 'function') {
      finalReducers[key] = reducers[key]
    }
  }

  const finalReducerKeys = Object.keys(finalReducers)

  let unexpectedKeyCache
  if (process.env.NODE_ENV !== 'production') {
    unexpectedKeyCache = {}
  }

  let sanityError

  //检测每个reducer是否是符合标准的reducer
  try {
    assertReducerSanity(finalReducers)
  } catch (e) {
    sanityError = e
  }

  return function combination(state = {}, action) {
    if (sanityError) {
      throw sanityError
    }

    //如果不是成产环境,做一些警告判断
    if (process.env.NODE_ENV !== 'production') {
      const warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache)
      if (warningMessage) {
        warning(warningMessage)
      }
    }

    let hasChanged = false
    const nextState = {} //下一个state树

    //遍历所有reducers,然后将每个reducer返回的state组合起来生成一个大的状态树,所以任何action,redux都会遍历所有的reducer
    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)

      //如果此reducer返回的新的state是undefined,抛出异常
      if (typeof nextStateForKey === 'undefined') {
        const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      nextState[key] = nextStateForKey
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    //如果当前action对应的reducer方法执行完后,该处数据没有变化,则返回原来的流程树
    return hasChanged ? nextState : state
  }
}

源码解释:

  • 这是一个标准的 reducer 函数,接受一个初始化状态 和 一个 action 参数;
  • 每次调用的时候会去遍历 finalReducers (有效的 reducer 列表),获取列表中每个 reducer 对应的先前状态: var previousStateForKey = state[key]
  • 看到这里就应该明白传入的 reducers 组合为什么 key 要和 store 里面的 state 的 key 相对应;
  • 然后得到当前遍历项的下一个状态: var nextStateForKey = reducer(previousStateForKey, action)
  • 然后把它添加到整体的下一个状态: nextState[key] = nextStateForKey
  • 每次遍历会判断整体状态是否改变: hasChanged = hasChanged || nextStateForKey !== previousStateForKey
  • 在最后,如果没有改变就返回原有状态,如果改变了就返回新生成的状态对象: return hasChanged ? nextState : state

相关文章

  • combineReducers原理

    简介 随着应用变得复杂,需要对 reducer 函数 进行拆分,拆分后的每一块独立负责管理 state 的一部分。...

  • redux的使用(三)--combineReducers

    combineReducers 使用combineReducers解决的目的: 1.将reducer函数拆分成多个...

  • 弄清原理之Redux combineReducers

    Redux reducer的作用 只用来处理state 变化,返回新的state reducer composit...

  • Redux源码阅读_3

    combineReducers.ts 函数重载声明 首先是对combineReducers函数的重载,重载了三个函...

  • redux源码

    createStroe.js applyMiddleware combineReducers

  • redux源码分析

    一、combineReducers 我一开始就看的是这个。这个文件只有这一个方法combineReducers,即...

  • Redux

    主要涉及的Api createStore combineReducers bindActionCreators a...

  • combineReducers理解

    1.combineReducers旨在整合切分后reducer,并将state树切分至各个reduce进行管理,这...

  • redux源码分析

    一、combineReducersredux.combineReducers(reducerMap) 的作用在于合...

  • Redux 源码初探

    标签: 源码解析,前端 Redux 1. Reducer combineReducers将多个reducer 合并...

网友评论

      本文标题:combineReducers原理

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