Redux踩坑系列--Reducer
wfatec opened this issue · comments
Reducer简介
reducer
实际上是真正作用于redux中state部分的纯函数,用于接收dispatch传过来的action对象,action对象通常是这种形式:
{
type: ADD_TODO,
payload: “balabala...”
}
其中payload
可以放入任何类型数据。当dispatch(action)
之后,就轮到reducer大展神威了,它会根据ADD_TODO进行匹配(一般通过switch/case
),执行相应的纯函数。
对于纯函数网上有很多的详解,这里简单说一下我的理解,其实就一个公式:f(x)===f(x)
;任意函数只要在任意情况下满足该公式,即纯函数。
那么reducer作为纯函数一般形式是什么样呢?如下:
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
case ADD_TODO:
return Object.assign({}, state, {
todos: [
...state.todos,
{
text: action.text,
completed: false
}
]
})
default:
return state
}
}
其实现的功能主要有:
- 接收原始
state
和dispatch
的参数action
- 根据
action
的type
属性找到对应的执行函数 - 若
action.type
未匹配,则原样返回接收的state
没错,这就是reducer的所有功能 :)
combineReducers
reducer本身没有什么问题,但随着项目的复杂度急剧增加,此时将所有action.type
的执行函数都写在一个文件里明显会带来维护上的困难,有没有什么方法能够使得各自模块的reducer能够各自维护,再统一合并到最终传给createStore的rootReducer中去呢?这个时候就到combineReducers
登场的时候了。
先来看一下combineReducers
的调用方式:
import { combineReducers } from 'redux'
import todos from './todos'
import counter from './counter'
export default combineReducers({
todos,
counter
})
其中todos和counter为已定义的分片reducer。
它主要实现的功能如下:
- 将不同模块的reducer函数合并到rootReducer
- 将reducer执行结果返回到该reducer传入combineReducers时对应的key下如此处的todos和counter
这里有一些坑需要着重提示一下:
所有传入的reducer会依次执行
这也就意味着不同reducer之间的执行结果会对之后的reducer执行造成影响,例如当todos中的reducer未匹配到对应的action时,如果在default中未返回传入state,或返回了错误的值,则在counter中将发生错误。因此我们在定义reducer时需要遵守如下约定:
- 入参中的state设置默认值
- 必须在switch/case最后定义default并返回传入的state
- 尽量避免不同reducer中使用相同的actionType
以上