ngrx обновить объект внутри массива

У меня есть магазин ngrx с массивом объектов. Я ищу обновление (изменение) объекта внутри массива, используя индекс массива. Мои данные ngrx будут выглядеть так:

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

Мне нужно обновить имя получателя на основе индекса массива. Итак, я реализовал следующую функцию редуктора

    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 ответа

Решение

При обновлении объекта в массиве я бы воссоздал массив со всеми исключенными объектами и добавил последний объект, которому требуется обновленное значение.

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'}))

--Редактировать

Добавлен фрагмент и изменена логика, поэтому порядок в списке не меняется.

Использовать 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
})

Это простой способ, не прибегая к глубокому погружению в объект состояния.

      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
  
   };
}),

Это предполагает, что вы передаете полный объект продукта в своем успешном действии.

Вы можете использовать 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.

Другие вопросы по тегам