【问题标题】:NGRX - How to update a field in an object in an array by reducer?NGRX - 如何通过reducer更新数组中对象中的字段?
【发布时间】:2020-03-26 05:24:51
【问题描述】:

如何通过 reducer 更新数组中的字段?我试过这个:

const customers = state.filteredCustomers;
for (const customer of customers) {
    for (const addr of customer.addresses) {
         addr.selected = false;
    }
}

return {
    ...state,
    filteredCustomers: customers,
};

但是它会抛出一个错误:

 TypeError: Cannot assign to read only property 'selected' of object '[object Object]'

最好的方法是什么?

【问题讨论】:

    标签: angular state ngrx reducers


    【解决方案1】:

    您可以使用 map 返回具有更新值的新客户数组。

    return {
      ...state,
      filteredCustomers: customers.map(customer => {
        // Either use a second map or another loop
        for (const addr of customer.addresses) {
          addr.selected = false;
        }
        return customer;
      })
    };
    

    【讨论】:

    • addr.selected = false; 又不行了!甚至用过地图。
    【解决方案2】:

    错误似乎是一些不可变的引用发生了变异。我会尝试这样的事情。

        const customers = state.filteredCustomers;
    
        const updatedCustomers = customers.map( customer => ({
    ...customer, addresses: customer.addresses.map( address => ({ ...address, selected: false 
    }));
    
        return {
            ...state,
            filteredCustomers: { ...state.filteredCustomers, ...updatedCustomers  },
        };
    

    【讨论】:

      【解决方案3】:

      您必须复制该州的每个级别。在这里,更新 x 层深度的嵌套状态可能会变得很尴尬。这就是为什么我会鼓励normalizing your state

      基本上,您必须遍历客户并复制属性,接下来您必须对地址执行相同操作并将 selected 设置为 false。

      return {
          ...state,
          filteredCustomers: state.filteredCustomers.map(c => ({
             ...c,
             addresses: c.adresses.map(a => ({...a, selected: false})
          })
      };
      

      第二种选择是使用 immer,Clean NgRx reducers using Immer 有一个库可以为 NgRx 8 中的 createReducer 函数执行此操作 - https://github.com/timdeschryver/ngrx-etc/#mutableon。通过这种方法,您可以使用问题中发布的代码 sn-p。

      【讨论】:

      • 但我的状态是一个类实例的数组。这使它们成为没有任何方法的对象
      【解决方案4】:
      import _ from 'lodash';
      

      并在您的代码中使用

      const tags: IAreaTag[] = _.cloneDeep(department.tags);
      

      然后返回常量

      所以在你的代码中

      const customers = _.cloneDeep(state.filteredCustomers);
      

      【讨论】:

        猜你喜欢
        • 2019-09-16
        • 2020-01-04
        • 1970-01-01
        • 2019-09-22
        • 2020-08-17
        • 1970-01-01
        • 1970-01-01
        • 2019-07-11
        • 1970-01-01
        相关资源
        最近更新 更多