0

也许我遗漏了一些完全明显的东西,但这让我今天感到不安。

假设我们有一个 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) => { ... }
});

这一切都很好,对吧?好吧,一开始给出的 state 中的 keytableSettings实际上应该由它自己的 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)
}

因此,在 state ( accountPageReducer) 部分的 reducer 之上,我们创建了 reducer:

// 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 可以处理一个新动作时,都需要将该动作添加到combineActions其所有父级中。不是最好的。

想法?

4

2 回答 2

2

您所在州的每个键都有自己的减速器。有些 reducer 非常简单,有些是由其他 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,
    });
于 2018-06-20T18:33:25.677 回答
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 .
于 2020-02-04T21:52:33.660 回答