8

我有一个带有对象数组的 ngrx 商店。我正在寻找的是,使用数组索引更新(修改)数组内的对象。我的 ngrx 数据看起来像,

    policies: {
        beneficiaries: {
            beneficiaries: [{
                    name: 'pqr'
                    age: 56
                },
                {
                    name: 'xyz'
                    age: 76
                }
            ]
        }
    }

我必须根据数组索引更新受益人姓名。所以我实现了以下reducer功能

    on(policiesActions.updateBeneficiaryPercentage, (state, action) => {
        return {
          ...state,
          beneficiaries: {
            ...state.beneficiaries,
            beneficiaries: {
              ...state.beneficiaries.beneficiaries,
              [action.index]: {
                ...state.beneficiaries.beneficiaries[action.index],
                name: action.value
              }
            }
          }
        };
      })

上述代码的问题是,在运行此代码后,我的商店结构更改为

policies: {
    beneficiaries: {
        beneficiaries: {
            0: {
                name: 'pqr'
                age: 1000
            },
            1: {
                name: 'xyz'
                age: 76
            }
        }
    }
}

请帮助我修复代码,以便我可以在不更改商店结构的情况下更新值。

4

4 回答 4

11

使用Array.map方法:

arr.map((value, index) => index === action.index ? {...value, name: action.value} : value) 

或者只是使用ngrx-etc,它可以让你以一种可变的方式改变你的状态,同时保持不可变

mutableOn(onAction, (state, action) => {
  state.arr[action.index].name = action.name
  return state
})
于 2020-05-03T07:13:46.323 回答
9

更新数组中的对象时,我会重新创建一个包含所有排除对象的数组,并附加最后一个需要更新值的对象。

const policies = {
  beneficiaries: {
    beneficiaries: [{
        name: 'pqr',
        age: 56
      },
      {
        name: 'xyz',
        age: 76
      }
    ]
  }
}

const updateObject = (state, action) => {

  if(!state.beneficiaries.beneficiaries[action.index]) {
    return state;
  }

  return {
    ...state,
    beneficiaries: {
      ...state.beneficiaries,
      beneficiaries: [
        ...state.beneficiaries.beneficiaries.slice(0, action.index),
        {
          ...state.beneficiaries.beneficiaries[action.index],
          name: action.value
        },
        ...state.beneficiaries.beneficiaries.slice(action.index + 1)
      ]
    }
  };
}

console.log(updateObject(policies, {index: 1, value: 'test'}))

- 编辑

添加了代码段并更改了逻辑,因此它不会更改列表顺序。

于 2020-05-02T19:12:36.407 回答
4

您可以使用 immer.js 生成新状态,而无需触及之前的状态。无需推出自己的解决方案,而且通过手动克隆前一个对象来重新创建对象很容易出错

import produce from "immer"

on(policiesActions.updateBeneficiaryPercentage, (state, action) => {
  return produce(state, draftState => {
    draftState.policies.beneficiaries.beneficiaries[action.index].name = action.value
  })
})

如果你想以一种功能性的方式来做,你可以尝试使用 ramda 的镜头示例

于 2021-03-25T12:18:50.623 回答
2

这是一种简单的方法,无需深入研究状态对象。

on(ProductActions.updateProductSuccess, (state, action): ProductState => {

  // define a constant and map over the existing state, inserting your new item,
  // then assign your new object as the new state.

  const updatedProducts = state.products.map(
  product => action.product.id === product.id ? action.product : product);
  return {
    ...state,
    products: updatedProducts
  
   };
}),

这假设您在成功操作中传递了一个完整的产品对象。

于 2021-05-28T15:48:34.660 回答