也许我错过了一些非常明显的东西,但今天这让我很困惑。
假设我们有一个Redux商店,其结构如下:
const state = {
...
pages: {
...
accountPage: {
currentTab: 'dashboard',
fetching: false,
tableSettings: {
sortDir: 'asc',
sortField: 'name'
}
}
}
}
所以显然有一个主减速器。。。
export default combineReducers({
...
pages: pagesReducer
...
});
然后页面的减速器有每页的减速器。。。
export default combineReducers({
...
accountPage: accountPageReducer
...
});
现在,我们终于来谈谈问题的实质,这个特定状态的减速器。
export default handleActions({
[setCurrentTab]: (state, action) => { ... },
[setIsFetching]: (state, action) => { ... }
});
这很好,对吧?好吧,在tableSettings
一开始给出的状态中的密钥实际上应该由它自己的reducer处理。这种模式可能在状态中存在多次,因此它被抽象为一个reducer创建函数:
const defaultState = {
sortDir: 'asc',
sortField: null
};
export const createTableSettingReducer (actions, extra ={}) => {
return handleActions({
[actions.changeSortDir]: (state, action) => ({ ...state, sortDir: action.payload }),
[actions.changeSortField]: (state, action) => ({ ...state, sortField: action.payload }),
...extra
}, defaultState)
}
因此,在状态部分(accountPageReducer
)的减缩器之上,我们创建了减缩器:
// pretend these actions were imported
const tableSettingsReducer = createTableSettingReducer({
changeSortDir: setSortDir,
changeSortField: setSortField
});
所以问题是,我把tableSettingsReducer
放在哪里?
这当然不起作用:
export default handleActions({
[setCurrentTab]: (state, action) => { ... },
[setIsFetching]: (state, action) => { ... },
tableSettings: tableSettingsReducer
});
它不起作用,因为handleActions
希望使用操作常量作为键,而不是状态中的实际键。
也没有地方可以使用combineReducers
,因为这个状态片只有一个嵌套的reducer。currentTab
和fetching
不需要自己的减速器,因此使用combineReducers
是徒劳的。
我知道最近redux-actions
开始支持嵌套减速器。。。但实际上并没有任何文档可以确切地显示应该如何完成,甚至没有描述实现这一目标所需的参数。
我可以使用combineActions
,并将handleActions
中的所有操作组合起来,用于嵌套reducer可以执行的每个操作。但这似乎不太干净。。。另外,如果嵌套减速器有自己的嵌套减速器怎么办?这意味着,每当这些减速器可以处理一个新的操作时,该操作都需要添加到combineActions
的所有父级中。不是最好的。
想法?
状态中的每个键都有自己的reducer。有些减速器非常简单,有些减速器本身由其他减速器组成。状态树的每个级别上的所有姐妹键都可以与combineReducers
组合。
const initialCurrentTab = 'dashboard';
const currentTabReducer = handleActions({
[setCurrentTab]: (state, action) => {
return action.payload;
},
}, initialCurrentTab);
const defaultFetchingState = false;
const fetchingReducer = handleActions({
[setIsFetching]: (state, action) => {
return action.payload;
},
}, defaultFetchingState);
export default combineReducers({
currentTab: currentTabReducer,
fetching: fetchingReducer,
tableSettings: tableSettingsReducer,
});
let say you have the initialState = { data : []}
let assume that the upcoming action has payload of an array
export the reducer as the following :
return handleActions({
["Action Type 1" ]: (state, { payload }) => {
return { ...state, data: [...state.data, ...payload ]} ;
},
["Action Type 1" ]: (state, { payload }) => {
return { ...state, data: [...state.data, ...payload ]} ;
},
}, initialSate );
import this reducer in your combine reducer .