资讯专栏INFORMATION COLUMN

redux源码分析之二:combineReducers.js

big_cat / 2695人阅读

摘要:欢迎关注源码分析系列文章源码分析之一源码分析之二源码分析之三源码分析之四源码分析之五文件对外暴露了一个函数,函数是的一个辅助性的函数,用于拆分里面的第一个参数函数。函数的返回值是一个函数,该函数是组合之后的一个标准的函数。

欢迎关注redux源码分析系列文章:
redux源码分析之一:createStore.js
redux源码分析之二:combineReducers.js
redux源码分析之三:bindActionCreators.js
redux源码分析之四:compose.js
redux源码分析之五:applyMiddleware

combineReducers.js文件对外暴露了一个函数combineReducers,combineReducer函数是redux的一个辅助性的函数,用于拆分createStore里面的第一个参数:reducer函数。combineReducer函数的返回值是一个函数,该函数是组合之后的一个标准的reducer函数。

一、分析combineReducers函数的参数:

combineReducers函数仅包含一个参数reducers,reducers是一个object类型参数,比如:

let reducers = {
    users: function getUsersReducer(){}, 
    userInfo: function getUserInfoReducer(){}
}
二、分析combineReducers返回之前做了什么:

1、从传入的参数里面提取出合法的reducers(reducers的每一个key对应的value值是函数,才是合法的子reducer),赋值给新的局部变量:finalReducers

  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}"`)
      }
    }
    //过滤出reducers对应的value值是function的key,将其放入finalReducers对象
    if (typeof reducers[key] === "function") {
      finalReducers[key] = reducers[key]
    }
  }

2、校验finalReducers, 判断其每一个子reducer是否能返回正常的子state

  //取出过滤出来的有效的keys列表
  const finalReducerKeys = Object.keys(finalReducers)

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

  let shapeAssertionError
  try {
    assertReducerShape(finalReducers)
  } catch (e) {
    shapeAssertionError = e
  }

assertReducerShape函数:

//确认reducer是否是合法的reducer,即返回的state是不是undefined,如果是undefined,则是非法reducer
function assertReducerShape(reducers) {
  Object.keys(reducers).forEach(key => {
    const reducer = reducers[key]
    const initialState = reducer(undefined, {type: ActionTypes.INIT})

    if (typeof initialState === "undefined") {
      throw new Error(
        `Reducer "${key}" returned undefined during initialization. ` +
        `If the state passed to the reducer is undefined, you must ` +
        `explicitly return the initial state. The initial state may ` +
        `not be undefined. If you don"t want to set a value for this reducer, ` +
        `you can use null instead of undefined.`
      )
    }

    const type = "@@redux/PROBE_UNKNOWN_ACTION_" + Math.random().toString(36).substring(7).split("").join(".")
    if (typeof reducer(undefined, {type}) === "undefined") {
      throw new Error(
        `Reducer "${key}" returned undefined when probed with a random type. ` +
        `Don"t try to handle ${ActionTypes.INIT} or other actions in "redux/*" ` +
        `namespace. They are considered private. Instead, you must return the ` +
        `current state for any unknown actions, unless it is undefined, ` +
        `in which case you must return the initial state, regardless of the ` +
        `action type. The initial state may not be undefined, but can be null.`
      )
    }
  })
}
三、分析combineReducers函数的返回值:

函数combination是一个标准的reducer函数,有初始化的state参数,和一个携带了actionType和数据的action对象。

function combination(state = {}, action) {
    //如果有非法的reducer,就直接报错喽
    if (shapeAssertionError) {
      throw shapeAssertionError
    }

    if (process.env.NODE_ENV !== "production") {
      const warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache)
      if (warningMessage) {
        warning(warningMessage)
      }
    }

    let hasChanged = false
    //定义新的nextState
    const nextState = {}
    // 1,遍历reducers对象中的有效key,
    // 2,执行该key对应的value函数,即子reducer函数,并得到对应的state对象,即子state
    // 3,将新的子state挂到新的nextState对象上,key不变
    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)
      if (typeof nextStateForKey === "undefined") {
        const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      nextState[key] = nextStateForKey
      //如果hasChanged为true,那就是true了   后面的判断是,只要有一次nextStateForKey!== previousStateForKey不同,就说明整个state不同
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    //如果state发生变化了,直接返回新的nextState,否则,还是返回旧的state
    return hasChanged ? nextState : state
  }
}
四、总结:

combineReducers函数其实就实现一个功能:将一个复杂的父reducer函数,根据state状态对应的key,拆分成几个子reducer;每个子reducer返回一个子state。多层嵌套的reducer树,可以对应组成一个多层嵌套的state状态树。

完整解析请参考我的github:https://github.com/abczhijia/...,如果对您有帮助,欢迎star,有任何问题也请指正。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89067.html

相关文章

  • 你想要的——redux源码分析

    摘要:大家好,今天给大家带来的是的源码分析首先是的地址点我接下来我们看看在项目中的简单使用,一般我们都从最简单的开始入手哈备注例子中结合的是进行使用,当然不仅仅能结合,还能结合市面上其他大多数的框架,这也是它比较流弊的地方首先是创建一个首先我们 大家好,今天给大家带来的是redux(v3.6.0)的源码分析~ 首先是redux的github地址 点我 接下来我们看看redux在项目中的简单使...

    enrecul101 评论0 收藏0
  • 解密Redux: 从源码开始

    摘要:接下来笔者就从源码中探寻是如何实现的。其实很简单,可以简单理解为一个约束了特定规则并且包括了一些特殊概念的的发布订阅器。新旧中存在的任何都将收到先前的状态。这有效地使用来自旧状态树的任何相关数据填充新状态树。 Redux是当今比较流行的状态管理库,它不依赖于任何的框架,并且配合着react-redux的使用,Redux在很多公司的React项目中起到了举足轻重的作用。接下来笔者就从源码...

    remcarpediem 评论0 收藏0
  • Redux 源码拾遗

    摘要:循环还没有结束,其中的某个对进行了添加或者删除,都会影响到此次循环的进行,带来不可预期的错误。 首先来一段 redux 结合 中间件 thunk、logger 的使用demo 了解一下应该如何使用 const redux = require(redux) const { createStore, combineReducers, bindActionCreators, ...

    CloudwiseAPM 评论0 收藏0
  • Redux 源码拾遗

    摘要:循环还没有结束,其中的某个对进行了添加或者删除,都会影响到此次循环的进行,带来不可预期的错误。 首先来一段 redux 结合 中间件 thunk、logger 的使用demo 了解一下应该如何使用 const redux = require(redux) const { createStore, combineReducers, bindActionCreators, ...

    zhangfaliang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<