Redux源码分析(2) — combineReducers
2023-05-20·5min
type
Post
summary
status
Published
category
tags
slug
date
May 20, 2023
password
icon
combineReducers.js
combineReducers用来合并多个reducer,它接收一个reducer数组,返回一个新的reducer代理函数。
大体结构如下:
可以发现,返回函数的参数和返回值,和单个reducer是一样的。
也就是说,在redux看来,只要入参和返回一样,都是一个东西,redux不关心其中的实现,只要能给回一个新的state既可以。
下面我们就来看看combineReducers是如何代理和组织多个reducer,并更新state。
第一步 浅拷贝reducers
这里做了以下几件事:
- 定义了一个finalReducers和finalReducerKeys,分别用来拷贝有效的reducers和keys
- 通过for循环拿到传入的每个reducer
- 在开发环境下,判断reducer是否为undefined,如果是,则提示开发者
- 判断每个reducer是否为函数,如果是,放入finalReducers中,否则忽略
第二步 检测finalReducers里的每个reducer是否都有默认返回值
这里调用了一个辅助函数assertReducerShape,它做以下两点事情:
- 检测每个reducer是否设置默认值
- 检测是否使用了"ActionTypes.INIT"等redux内置的type类型
主要工作流程如下:
- 通过循环finalReducers,拿到每个reducer
- 调用每个reducer,参数为(undefined, { type: ActionTypes.INIT }), 如果返回默认值为undefined,则可以认为该reducer没有设置默认值,抛出异常。
- 调用每个reducer,参数为(undefined, { type: type: ActionTypes.PROBE_UNKNOWN_ACTION() }), 如果返回默认值为undefined,则可以认为该reducer使用了redux内置的type类型,抛出异常。
第三步 返回一个代理函数,代理所有reducer
第三步整体代码:
可以看到第一步就是检查shapeAssertionError是否存在,也就是看有没有没设置默认值的reducer,如果有,则抛出异常,后面都不再执行。
接着如果在开发环境下,会调用一个辅助函数getUnexpectedStateShapeWarningMessage,做一个异常检测,找出state里面没有对应reducer的key,并提示开发者做调整
getUnexpectedStateShapeWarningMessage代码如下:
getUnexpectedStateShapeWarningMessage接收四个参数inputState(state)、reducers(finalReducers)、action(action)、unexpectedKeyCache(unexpectedKeyCache),unexpectedKeyCache是上一次检测inputState得到的其里面没有对应的reducer集合里的异常key的集合。
整体逻辑如下:
- 前置条件判断,保证reducers集合不为{}以及inputState为简单对象
- 检测state里的所有key,如果reducers里没有对应的key,则把这个key放入unexpectedKeyCache
- 如果是替换reducer的action,跳过第四步,不打印异常信息
- unexpectedKeyCache里如果不为空,将所有异常的key打印出来,提示开发者做调整
接着看剩余的代码:
- 声明hasChanged和nextState,分别表示state是否有变化,存放新的state。
- 遍历reducers集合,将每个reducer对应的原state传入其中,得出其对应的新的state
- 对得到的新state做校验,如果返回的是undefined,提示开发者,如果想返回一个空值,用null而不是undefined。
- 将新的state放入nextState中
- 检查新旧state是否发生变化,如果发生变化,则返回nextState,否则返回state。
combineReducers小结
combineReducers整体逻辑不算复杂,主要是对所有reducer做了代理,并且做了以下的异常检测:
- 确保所有reducer都是函数类型
- 确保所有reducer都有默认值
- 检测state里的所有key,如果reducers里没有对应的key,提示开发者调整
然后调用每个reducer,并传入key值相同的state,得到新的state。
最后将所有得到的state合并成新的state集合一起返回。