也许我错过了一些完全明显的东西,但今天这让我感到沮丧。
假设我们有一个Redux商店,结构如下:
loadApiCoins({ commit }) {
Vue.axios({
method: 'get',
url: 'https://api.coinmarketcap.com/v1/ticker/',
headers: {
'Authorization': '',
},
}).then(...)
},
所以显然有一个主要的减速器......
const state = {
...
pages: {
...
accountPage: {
currentTab: 'dashboard',
fetching: false,
tableSettings: {
sortDir: 'asc',
sortField: 'name'
}
}
}
}
然后页面的reducer有每页的reducer ...
export default combineReducers({
...
pages: pagesReducer
...
});
现在我们终于明白了问题的关键,这个特定州的减速器。
export default combineReducers({
...
accountPage: accountPageReducer
...
});
这一切都很好吗?好吧,在export default handleActions({
[setCurrentTab]: (state, action) => { ... },
[setIsFetching]: (state, action) => { ... }
});
开始时给出的状态中的键实际上应该由它自己的reducer处理。这种模式可能在状态中存在很多次,因此它被抽象为reducer创建函数:
tableSettings
因此,在状态部分(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)
}
)的reducer之上,我们创建了reducer:
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
,因为这个状态片只有一个嵌套的reducer。 combineReducers
和currentTab
不需要自己的reducer,因此使用fetching
毫无结果。
我知道最近combineReducers
开始支持嵌套的Reducer ...但是实际上没有任何文档可以显示它应该如何完成,甚至描述实现它所需的参数。
我可以使用redux-actions
,并将combineActions
中的所有操作组合起来,用于嵌套reducer可以执行的每个操作。但这似乎不是很干净......另外,如果嵌套的reducer有它自己的嵌套Reducer怎么办?这意味着每次这些减速器都可以处理新动作时,需要将该动作添加到其所有父级中的handleActions
。不是最好的。
思想?
答案 0 :(得分:2)
处于状态的每个键都有其自己的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,
});
答案 1 :(得分:0)
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 .