Redux操作句柄操作嵌套的Reducer



也许我错过了一些非常明显的东西,但今天这让我很困惑。

假设我们有一个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。currentTabfetching不需要自己的减速器,因此使用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 .

最新更新