Как обновить или удалить вложенный объект внутри сущностей ngrx?
Как обновить или удалить вложенный объект внутри сущностей ngrx, например, я хочу удалить первый элемент, который имеет 19 id из (charter.entities.scopes.data), как это показано в приведенном ниже хранимом объекте json внутри моего магазина ngrx
charter: {
ids: [
1
],
entities: {
'1': {
id: 1,
projectName: 'Some Project',
projectCode: '899',
projectUniqueCode: '674a9596-50ee',
projectStatus: 'construction',
budgetCode: 'CC34',
projectTypeOne: 'Goods',
projectTypeTwo: 'New',
donorName: 'Elza Hills',
scopes: {
data: [
{
id: 19,
module: 'Miss Cassandra Cartwright I',
description: 'In tempore quia asperiores aut ea cum optio minima nemo est et aspernatur est repudiandae voluptas ipsum.',
time: '2018-01-23 15:37:36'
},
{
id: 43,
module: 'Leanne Douglas',
description: 'Occaecati facere eligendi esse esse nostrum in et vitae assumenda molestias omnis quis sit qui aut omnis est.',
time: '2018-01-23 15:37:36'
},
]
},
assumptions: {
data: [
{
id: 29,
assumption: 'Doloremque quo nihil minima ad optio perspiciatis asperiores debitis mollitia at debitis porro quia nam accusantium illo consequatur labore cum.',
comments: 'Inventore ut pariatur id laboriosam recusandae soluta quo sunt impedit aut velit.'
},
{
id: 164,
assumption: 'Dolores quam aut possimus sint fugiat natus quos quaerat saepe facilis harum molestiae.',
comments: 'Cumque quis magni illo dolore quas nam officiis dolores enim soluta doloribus in sed eum ut sunt.'
},
]
},
Редуктор
export interface State extends EntityState<ProjectsCharter> {
isLoading: boolean;
isLoaded: boolean;
selectedProjectsId: any;
}
export const adapter: EntityAdapter<ProjectsCharter> = createEntityAdapter({
selectId: (state: ProjectsCharter) => state.id,
sortComparer: false
});
export const initialState = adapter.getInitialState({
isLoading: false,
isLoaded: false,
selectedProjectsId: null
});
export function reducer(state = initialState, action: CharterActions) {
switch (action.type) {
case CharterActionTypes.loadCharterSuccess:
return {
...adapter.addOne(action.payload['data'], state),
isLoading: false,
isLoaded: true
};
case CharterActionTypes.updateScopeOnParent:
const scopeEntity = { ...state.entities[action.payload.param] };
scopeEntity.scopes.data = scopeEntity.scopes.data.map(item => {
if (item.id === action.payload.id) {
item.module = action.payload.module;
}
return item;
});
return {
...adapter.updateOne(scopeEntity, state)
};
default:
return {
...state
};
}
}
Я могу обновить и изменить объект nestad с помощью этого редуктора, но проблема в том, что 1- он немного сложен, а также показывает меня в терминале во время компиляции error TS2339: Property 'map' does not exist on type 'Scope'.
также Argument of type '{ id: string; projectName: string; projectStatus: string; projectCode: string; projectUniqueCode:...' is not assignable to parameter of type 'Update<ProjectsCharter>'.
2 ответа
Я настоятельно советую вам изменить свой магазин и нормализовать его. Посмотрите здесь: https://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html
При таком подходе у вас будут менее сложные редукторы, как описано здесь https://redux.js.org/docs/recipes/reducers/UpdatingNormalizedData.html
С магазином, сформированным таким образом, вам придется построить сложный редуктор.
Согласно моей логике, следующие моды редуктора должны по крайней мере устранить ошибку TS2339.
Этот бит
Аргумент типа '{ id: string; имя_проекта: строка; projectStatus: строка; projectCode: string; projectUniqueCode:...'нельзя назначить параметру типа'Update'
просто говорит вам (бесполезно), что adapter.updateOne
требует первого параметра шаблона { id, changes }
но вы просто даете это changes
,
export function reducer(state = initialState, action: CharterActions) {
switch (action.type) {
case CharterActionTypes.loadCharterSuccess:
...
case CharterActionTypes.updateScopeOnParent:
const id = action.payload.param;
const entities = {...state.entities};
const original = entities[id];
const newScopes = original.scopes.data.map(item => {
if (item.id === action.payload.id) {
item.module = action.payload.module;
}
return item;
});
const changes = { scopes: { data: newScopes }} // Partial<ProjectsCharter>
return {
...adapter.updateOne({ id, changes }, state)
};
}
default:
...
}
}
Позвольте мне предварить это, сказав, что идеальное решение - нормализовать ваши сущности с помощью чего-то вроде normalizr. Тем не менее, вот решение, которое мне подходит:
- Сделайте глубокий клон объекта состояния
- Используйте Javascript
delete
метод клонированного объекта - Передайте этот новый объект как новое состояние
Итак, предположим, что ваше состояние выглядит примерно так:
{
entities: {
'1': {
prop1: 'val1',
nested: {
'1': {
prop1: 'val1'
},
'2': {
prop2: 'val2'
}
}
}
}
Если ваша цель - удалить entities[1].nested[1]
просто используйте следующий код (обратите внимание, что я использую библиотеку lodash):
import * as _ from 'lodash'
on(Actions.sampleDeleteAction, (state) => {
const clonedState = _.cloneDeep(state);
delete clonedState.entities[1].nested[1];
return { ...clonedState };
}
Очевидно, вы хотели бы добавить props
к вашему действию, которые содержат необходимые значения индекса, которые вы используете для удаления, вместо того, чтобы явно использовать индексы, как в примере entities[1].nested[1]
.