如何使用嵌套对象编写状态化简器

how to write state reducer with nested objects

本文关键字:状态 何使用 嵌套 对象      更新时间:2023-09-26

我的redux状态树的心理模型看起来像这样:

{
  selectedDepartment: 'Chemistry',
  purchasesByDepartment: {
    Chemistry: {
      purchaseOrders: {
        ...
      },
      invoices: {
        ...
      }
    },
    Biology: {
      purchaseOrders: {
        ...
      },
      invoices: {
        ...
      }
    },
    ...(another department, etc)
  }
}

这是我的减速机

const purchasesByDepartment = (state = {}, action) => {
  switch (action.type) {
    case RECEIVE_POS:
      return Object.assign({}, state, {
        [action.department]: {
          purchaseOrders: action.json
          // but this wipes out my invoices          
        }
      })
    case RECEIVE_INVOICES:
      return Object.assign({}, state, {
        [action.department]: {          
          invoices: action.json
          // but this wipes out my purchaseOrders
        }
      })
    default:
      return state
  }
}

您可以在每个部门中看到,我有一个采购订单和一个发票密钥。我正在尽力编写我的化简器,使其不会改变我的状态,但我没有运气,因为每个操作当前都会清除另一个键。

我启动两个动作:RECEIEVE_POS、RECEIVE_INVOICES。

当我的操作RECEIVE_POS被派出时,我可以使用采购订单创建一个新状态,但这会清除我的发票。

当我的操作RECEIVE_INVOICES被派出时,我可以使用发票创建一个新状态,但这会清除我的采购订单。

如何编写我的减速器,以便我可以保留我的采购订单和发票(如果它们已经存在于我的州)?

您可以先通过应用更改为部门创建新状态,然后将其合并到化简器状态中。

const purchasesByDepartment = (state = {}, action) => {
  switch (action.type) {
    case RECEIVE_POS:
      let nextPOS = Object.assign({}, state[action.department] || {}, {
        purchaseOrders: action.json
      });
      return Object.assign({}, state, nextPOS);
    default:
      return state
  }
}

就我个人而言,我喜欢通过使用immutablejs使我的整个商店不可变,这使得这样的操作(以及一堆其他事情)变得微不足道:

return state.setIn([action.department, 'purchaseOrders'], action.json]);

我使用点差运算符(表示为 ...arrayName )来实现这一点。它是 es6,我用 babel 启用该功能。

Spread 会将数组分散到其元素中,它比 Object.assign 更易于人类阅读。

使用您的上下文,对于我的化简器中的简单场景,我只是像这样:

return {
    ...state,
    selectedDepartment: 'Chemistry or whatever' 
}

这将返回一个由状态组成的数组,加上被给定值覆盖的 selectedDepartment。

对于嵌入对象,您可以这样说:

return {
    ...state,
    purchasesByDepartment: {
        ...state.purchasesByDepartment,
        Chemistry: {
            ...state.purchasesByDepartment.Chemistry,
            invoices: {
                {your new invoices object comes here}
            }
        }
    }
}

对象分布计算的属性名称相结合帮助我解决了这个问题

case RECEIVE_POS:
  return {
    ...state,
    [action.department]: {
      ...state[action.department],
      purchaseOrders: action.json
    }
  }
case RECEIVE_INVOICES:
  return {
    ...state,
    [action.department]: {
      ...state[action.department],
      invoices: action.json
    }
  }