Redux中的action只是表明了在应用中发生了什么,但是并没有对数据state进行处理,Reducers就是用来处理数据的。
因为在Redux中只有一个state对象,所以在设计state时我们要尽量将我们必须的数据保存在state中。
Reducers是如何处理action的
下面我们以具体示例来看下reducer是如何在接收到action对数据进行处理的。
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
default:
return state
}
}
其中todoApp就是我们定义的Reducers,它接收两个参数:当前state的值和action,然后基于action的type决定如何处理state。
注意:我们不会直接对state进行修改,而是重新创建一个对象,这样就可以使得我们能够获取历史数据。
Reducers的拆分
当我们的功能越来越多时,如果我们只有一个Reducers,那么这个Reducers的职责会越来越大。这个时候我们就要考虑将这个Reducers进行拆分。
参考Redux官方文档,假设我们现在的Reducers如下所示:
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
default:
return state
}
}
function visibilityFilter(state = SHOW_ALL, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return action.filter
default:
return state
}
}
function todoApp(state = {}, action) {
return {
visibilityFilter: visibilityFilter(state.visibilityFilter, action),
todos: todos(state.todos, action)
}
}
如代码所示,todos和visibilityFilter是我们拆分出的两个Reducers,因为它们只是关注state上的部分数据,并不是全部的。所以我们通过todoApp只传递它们需要的数据,并在所有的Reducers执行完毕后使用最新数据更新state。当然了,Redux也提供为我们提供了combineReducers()来实现。
通过combineReducers重新实现todoApp,如下所示:
import { combineReducers } from 'redux'
const todoApp = combineReducers({
visibilityFilter,
todos
})
export default todoApp
等价于
import { combineReducers } from 'redux'
const todoApp = combineReducers({
visibilityFilter:visibilityFilter,
todos:todos
})
export default todoApp
下面我们来看下combineReducers的关键源码,:
function combineReducers(reducers) {
//1、首先获取Reducers的key
//2、基于key,过滤出value为function的Reducers
const reducerKeys = Object.keys(reducers)
const finalReducers = {}
for (let i = 0; i < reducerKeys.length; i++) {
const key = reducerKeys[i]
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
const finalReducerKeys = Object.keys(finalReducers)
//在store.dispatch被执行时,combination方法会被执行。
//1、初始化hasChanged为false
//2、循环调用每个reducers,基于Reducers的key获取其关心的数据
return function combination(state = {}, action) {
let hasChanged = false
const nextState = {}
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)
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
}
}