由于redux的单一状态原则,只有一个store,但是我们有很多数据,如果全部集中在一个reducer函数中来处理就会非常的难以维护,在项目中我们一般会拆分成很多reducer,然后在创建store的时候,借助combineReducers对这些reducer进行合并,返回一个总的reducer,那么combineReducers是什么意思,他又怎么来用呢?
借助官网的案例:现在有三个action type分别是SET_VISIBILITY_FILTER,ADD_TODO,TOGGLE_TODO那么就需要分别戳action.type进行判断属于哪个,然后分别做处理。
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
}
]
})
case TOGGLE_TODO:
return Object.assign({}, state, {
todos: state.todos.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
})
}
return todo
})
})
default:
return state
}
}
但是我们会发现这个代码非常的冗长,根据数据结构其实可以发现可以分成两类,一类是对visibilityFilter来做改变,一个是对todos来做改变,那么我们就可以拆分成两个函数:
一个是处理todos:
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
case TOGGLE_TODO:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
})
}
return todo
})
default:
return state
}
}
一个处理VisibilityFilters:
function visibilityFilter(state = SHOW_ALL, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return action.filter
default:
return state
}
}
那么我们其实可以发现在todos函数中接收到的state是一个数组,在visibilityFilter接收到的state是一个字符串,那么这样就可以对不同的数据用不同的reducer分别做处理,之后合并成一个reducer就可以了:
function todoApp(state = {}, action) {
return {
visibilityFilter: visibilityFilter(state.visibilityFilter, action),
todos: todos(state.todos, action)
}
}
那么总的reducer就是todoApp,返回一个对象,分别存储了visibilityFilter的值和todos的值,在visibilityFilter函数中传入state.visibilityFilter和action,在todos函数传入state.todos和action。那么在每次dispatch一个对象以后,都会执行todoApp函数,返回一个新的state对象。
那么就可以借助Redux 提供了combineReducers() 工具类来做上面 todoApp 做的事情,这样就能消灭一些样板代码了。
import { combineReducers } from 'redux'
const todoApp = combineReducers({
visibilityFilter,
todos
})
export default todoApp
和上面完全等价,也就是说会生成一个state包含visibilityFilter、todos的变量,并且会在初始化和后续更新的时候都用同名函数来进行更新,更新的时候把上次的state对应这个变量的数值传入。
或者如果你想换一个变量名,那么可以:
const reducer = combineReducers({
a: doSomethingWithA,
b: processB,
c: c
})
function reducer(state = {}, action) {
return {
a: doSomethingWithA(state.a, action),
b: processB(state.b, action),
c: c(state.c, action)
}
}
两种完全等价。那么这样你之后获取state的数据就得store.getState().a来获取