Redux reducers——改变深度嵌套状态

Posted

技术标签:

【中文标题】Redux reducers——改变深度嵌套状态【英文标题】:Redux reducers -- changing deeply-nested state 【发布时间】:2016-06-27 02:58:41 【问题描述】:

我正在努力思考如何在 redux 中更改深度嵌套的状态。对我来说,组合 reducer 并更改这些部分的第一级状态属性是有意义的。我不太清楚的是如何更改深度嵌套属性的状态。 假设我有一个购物车应用程序。以下是我的状态:


    cart: 
      items: []
    ,
    account: 
      amountLeft: 100,
      discounts: 
        redeemed: [],
        coupons: 
          buyOneGetOne: false
        
      
      

当用户输入代码时,假设他们可以兑换“buyOneGetOne”优惠券,并且该值应该变为 true。 我有一个用于购物车的减速器和另一个用于帐户的减速器。对于一级属性(比如我正在清理购物车的物品),我只需在减速器中执行以下操作:

case 'EMPTY_CART':
  return Object.assign(, state, items: []);

但是,为了更改 buyOneGetOne,我似乎首先需要对优惠券执行 Object.assign(因为 buyOneGetOne 已修改),然后对折扣执行 Object.assign(因为我已修改优惠券),然后最后发出动作,以便 reducer 可以对帐户执行 Object.assign (因为折扣现在已更改)。不过,这似乎非常复杂且容易出错,这让我相信一定有更好的方法。

我做错了吗?似乎减速器仅用于修改状态的根级别属性(如购物车和帐户),并且我不应该有一个接触帐户内部状态的减速器(如折扣减速器),因为帐户已经有一个减速器.但是,当我只想更改状态树下方的一个属性时,将每个对象从该更改一直到对象链向上合并到根的子级就变得很复杂...

你能/应该在减速器内部有减速器吗,就像在这种情况下有一个折扣减速器?

【问题讨论】:

【参考方案1】:

是的,分离这些减速器是正确的。实际上,如果您担心其中一些操作需要更改其他 reducer,您可以对其他常量做出反应,或者只是调度另一个操作。

I've created a library 来解决这个问题 - 允许轻松组合,避免冗长的语法以及合并结果。 因此,您的示例将如下所示:

import  createTile, createSyncTile  from 'redux-tiles';

const cartItems = createSyncTile(
  type: ['account', 'cart'],
  fn: ( params ) => ( items: params.items )
);

const coupons = createSyncTile(
  type: ['account', 'coupons'],
  fn: ( params ) => params,
);

const reedemedCoupons = createSyncTile(
  type: ['account', 'reedemedCoupons'],
  fn: ( params ) => params.coupons
);

const account = createTile(
  type: ['account', 'info'],
  fn: ( api ) => api.get('/client/info')
);

使用这种策略,每个组件都是原子的,您可以轻松地创建新组件和调度其他组件,而不会影响其他组件,当您的“图块”遵循单一职责原则时,将来重构和删除某些功能会变得更容易。

【讨论】:

看起来棒极了。自 2017 年以来我没有看到任何更新,发生了什么?有没有其他类似的东西?【参考方案2】:

你应该为每一层深度嵌套combinedReducers

【讨论】:

【参考方案3】:

你绝对可以在reducers里面有reducer;事实上,redux 演示应用就是这样做的:http://redux.js.org/docs/basics/Reducers.html

例如,您可以创建一个名为 `discounts' 的嵌套 reducer:

function discounts(state, action) 
    switch (action.type) 
        case ADD_DISCOUNT:
            return state.concat([action.payload]);

        // etc etc
    

然后在你的账号reducer中使用这个reducer:

function account(state, action) 
    switch (action.type) 
        case ADD_DISCOUNT:
            return 
                ...state,
                discounts: discounts(state.discounts, action)
            ;

         // etc etc
    


要了解更多信息,请查看 Dan 本人的 egghead.io redux series,特别是 reducer composition 视频!

【讨论】:

这很酷,我没有意识到这一点。然而,目标不也是尽可能平坦的状态树吗?嵌套减速器和扁平状态树之间的平衡点在哪里? 购物车示例github.com/reactjs/redux/tree/master/examples/shopping-cart/src/…的新链接

以上是关于Redux reducers——改变深度嵌套状态的主要内容,如果未能解决你的问题,请参考以下文章

Redux reducer - 它会改变状态吗?

React Redux Reducer 触发但不改变状态

更新深度嵌套的 react redux 状态数组元素

Redux 动作/reducers 与直接设置状态

React Redux reducer 未更新状态

将项目添加到 redux-toolkit 中的嵌套数组