【发布时间】:2018-03-21 06:07:10
【问题描述】:
也许我遗漏了一些非常明显的东西,但今天这让我很头疼。
假设我们有一个结构如下的 Redux 存储:
const state = {
...
pages: {
...
accountPage: {
currentTab: 'dashboard',
fetching: false,
tableSettings: {
sortDir: 'asc',
sortField: 'name'
}
}
}
}
那么显然有一个主reducer...
export default combineReducers({
...
pages: pagesReducer
...
});
那么pages的reducer对每个页面都有reducer...
export default combineReducers({
...
accountPage: accountPageReducer
...
});
现在我们终于进入了问题的核心,这个特定状态的 reducer。
export default handleActions({
[setCurrentTab]: (state, action) => { ... },
[setIsFetching]: (state, action) => { ... }
});
没关系吧?好吧,一开始在tableSettings 给出的状态键实际上应该由它自己的reducer 处理。这种模式在 state 中可能存在很多次,因此被抽象为一个 reducer-creating 函数:
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不需要自己的reducer,所以用combineReducers是徒劳的。
我知道最近 redux-actions 开始支持嵌套减速器...但实际上并没有任何可用的文档准确说明它应该如何完成,甚至没有描述实现它所需的参数。
我可以使用combineActions,并将handleActions 中的所有操作组合起来,用于嵌套reducer 可以执行的每个操作。但这似乎不是很干净......另外,如果嵌套减速器有它自己的嵌套减速器怎么办?这意味着每次这些 reducer 可以处理一个新动作时,都需要将该动作添加到其所有父级中的combineActions。不是最好的。
想法?
【问题讨论】:
标签: redux nested reducers redux-actions