jinjiaxing/Blog

Redux源码分析(二) 之combineReducers

Opened this issue · 0 comments

上一篇我们看完了createStore这个自认为最为核心的文件之后,我们再来看下combineReducers.js这个文件,其他它最主要的作用就是合并多个reducer,因为在createStore中的第一个参数就是一个reducer,而平时我们开发过程中如果将全部状态都写在一个文件中有一些过于庞大且不好管理,因此我们可以先拆开去写reducer,之后再用combineReducers合并就ok了,下面我们来看代码

import ActionTypes from './utils/actionTypes'
import warning from './utils/warning'
import isPlainObject from './utils/isPlainObject'

function getUndefinedStateErrorMessage(key, action)
function getUnexpectedStateShapeWarningMessage(
  inputState,
  reducers,
  action,
  unexpectedKeyCache
)
// 这个方法用于检测用于组合的reducer是否是符合redux规定的reducer
function assertReducerShape(reducers)

前面三个函数主要是针对一些警告处理的提示信息函数,另外import了三个文件,第一个ActionTypes只是初始化时定义的action名称没什么了,以后我们也可以按照这种方式去存actionTypeName,第二个也是一个警告函数了,第三个是判断对象是否为plain object,说白一点就是最简单的对象不存在继承,没有proto。下面的combineReducers也就是该文件的核心

export default function combineReducers(reducers) {
    // 遍历全部的reducers,得到一个key数组
    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全部内容拷贝到finalReducers中,日后对该对象进行操作
        if (typeof reducers[key] === 'function') {
            finalReducers[key] = reducers[key]
        }
    }
    // 遍历finalReducers的keys
    const finalReducerKeys = Object.keys(finalReducers)

    // 意外key的缓存对象
    let unexpectedKeyCache
    if (process.env.NODE_ENV !== 'production') {
        unexpectedKeyCache = {}
    }

    // 断言error
    let shapeAssertionError
    try {
        assertReducerShape(finalReducers)
    } catch (e) {
        shapeAssertionError = e
    }

    // 这些内容才是关键合并的地方,返回的就是一个函数,而这个函数就是一个reducer,所以参数也是state和action
    return function combination(state = {}, action) {
        // 依然是异常处理
        if (shapeAssertionError) {
            throw shapeAssertionError
        }

        // 异常处理警告
        if (process.env.NODE_ENV !== 'production') {
            const warningMessage = getUnexpectedStateShapeWarningMessage(
                state,
                finalReducers,
                action,
                unexpectedKeyCache
            )
            if (warningMessage) {
                warning(warningMessage)
            }
        }

        let hasChanged = false
        const nextState = {}
        // 遍历全部的reducer
        for (let i = 0; i < finalReducerKeys.length; i++) {
            const key = finalReducerKeys[i]
            const reducer = finalReducers[key]
            const previousStateForKey = state[key]
            // 执行reducer,得到每个reducer计算后的状态对象
            const nextStateForKey = reducer(previousStateForKey, action)
            if (typeof nextStateForKey === 'undefined') {
                const errorMessage = getUndefinedStateErrorMessage(key, action)
                throw new Error(errorMessage)
            }
            // 把全部的状态对象组合成一个 新的状态对象
            nextState[key] = nextStateForKey
            hasChanged = hasChanged || nextStateForKey !== previousStateForKey
        }
        // 判断是否变化,有变化则返回最新的state
        return hasChanged ? nextState : state
    }
}

其实总结起来也很简单,就是遍历全部的reducer,通过执行每个reducer得到状态对象,最后在将各个得到的计算值组合成一个大的状态对象,因为reducer本身的作用通过action得到变化的最新的状态对象。

更多内容可参考我的https://github.com/jinjiaxing/Blog
react最新脚手架和react组件库请参考:https://github.com/jinjiaxing/react-template-easily