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.