【问题标题】:How to use the initial state at root level in combineReducers?如何在 combineReducers 中使用根级别的初始状态?
【发布时间】:2017-06-06 11:35:41
【问题描述】:

我需要使用单个 reducer 更新应用程序状态的多个属性。后来我使用了combineReducers redux 帮助器,它结合了所有的减速器。问题是,除了我需要将整个状态传递给的那个之外,所有其他减速器都从状态的根(即属性)向下运行一层。

如何使用combineReducers函数传递根状态?

const App = combineReducers({
  pages: combineReducers({
    browse: combineReducers({
      numOfItems: loadMoreItems,
      filter: setFilter
    })
  }),
  <rootState>: openPage,
  favoriteItems: addItemToFavorites,
  inBasketItems: addItemToBasket
})

我在&lt;rootState&gt; 中放置什么?

【问题讨论】:

标签: javascript ecmascript-6 redux


【解决方案1】:

Redux 文档在 Structuring Reducers - Beyond combineReducers 部分中介绍了这个主题。基本上,你需要使用的不仅仅是just combineReducers 来完成你想要的。我还在我最近的博文Practical Redux, Part 7: Form Change Handling, Data Editing, and Feature Reducers 中给出了编写一些自定义reducer 结构逻辑的示例。

【讨论】:

    【解决方案2】:

    经过一些重构,我发现在这种情况下最好不要使用combineReducers。相反,我像这样构建了我的根减速器:

    const App = (state = initialState, action) => {
      state = Object.assign({}, state)
    
      switch (action.type) {
        case OPEN_PAGE:
          state = openPage(state, action)
        case LOAD_MORE_ITEMS:
          state.pages.browse.numOfItems = loadMoreItems(state.pages.browse.numOfItems, action)
        case SET_FILTER:
          state.pages.browse.filter = setFilter(state.pages.browse.filter, action)
        case ADD_ITEM_TO_FAVORITES:
          state.favoriteItems = addItemToFavorites(state.favoriteItems, action)
        case ADD_ITEM_TO_BASKET:
          state.inBasketItems = addItemToBasket(state.inBasketItems, action)
      }
    
      return state
    }
    

    如果在状态的特定部分工作的任何减速器更复杂,那么使用combineReducers 可能是有意义的,但它对我来说就像这样。为了便于阅读,我仍然在 sub-reducers 中保留了一些样板,如下所示:

    const loadMoreItems = (state = initialState.pages.browse.numOfItems, action) => {
      switch (action.type) {
        case LOAD_MORE_ITEMS:
          return state = action.number
        default:
          return state
      }
    }
    

    所以基本上我保留了状态初始化和动作名称,因为这样更容易理解这个 reducer 的全部内容。

    【讨论】:

    • 小心那里的逻辑。调用其他函数的想法是正确的,但是您正在用结果改变状态。您需要确保复制每一层 的嵌套。请参阅redux.js.org/docs/recipes/reducers/ImmutableUpdatePatterns.html 了解更多信息。
    • @markerikson ,您的意思是可以异步调用减速器吗?因为 reducer 一次只处理一个动作,这意味着状态只会发生这么多变化。
    • 呃……不,我说的根本不是这个。我的意思是当你想更新state.pages.browse.filter时,你实际上需要复制browse、pages和state。否则,您已经直接改变了现有的 browse 对象。请阅读链接页面以获得解释,特别是本小节:redux.js.org/docs/recipes/reducers/…。
    • 如果你看一下代码的开头——我实际上是在使用state = Object.assign({}, state) 来复制整个状态,然后我改变了副本。这能解决问题吗?
    • 不,因为这仍然只是复制 first 级别。您需要复制所有层的嵌套。同样,我链接的页面解释了这个想法,并给出了如何正确更新嵌套字段的示例。
    【解决方案3】:

    如果我理解你的话,你可以定义另一个名为 rootState 的减速器,然后简单地将它传递给组合减速器,就像任何其他减速器一样。

    另一方面,如果你想用相同的 action 更新多个 reducer,你只需要在每个 reducer 中添加一个 case,action 应该会改变 state。

    【讨论】:

    • 谢谢,但是在这种情况下 rootReducer 会是什么样子? .. 关键是 Redux 会在传递给 store 的初始状态中查找指定的 keys,如果找不到“favoriteItems”或“inBasketItems”,他会抱怨。
    • combine reducer 中的所有键都必须有一个 redux reducer 作为值,并且每个 reducer 在第一次初始化时都应该有一个默认状态。 Si 在这种情况下,“favoriteItems”将具有“addItemToFavorites”reducer 作为值,这将具有默认状态值,否则永远不会返回 undefined。
    • 我不确定你是否理解我的问题。你知道combineReducer中的keys是什么意思吗?
    猜你喜欢
    • 2020-12-20
    • 1970-01-01
    • 2019-10-30
    • 2021-04-05
    • 1970-01-01
    • 2019-10-05
    • 2019-05-08
    • 2022-07-13
    • 1970-01-01
    相关资源
    最近更新 更多