Удаление данных из вложенных объектов без мутирования
Есть ли элегантный способ удаления объекта из массива, который является частью массива?
Я работаю с React и Redux какое-то время, но застрял несколько часов каждый раз, когда мне приходится удалять или вставлять данные без изменения состояния.
Редуктор представляет собой массив, содержащий объекты, у которых есть ID и другой массив с объектами, например:
[
{ id:123,
items:[
{ id: abc,
name: albert
},
...
]
},
...
]
Я получаю оба идентификатора и должен удалить элемент с идентификатором abc
.
Ответы
Ответ 1
Чтобы удалить элемент из массива по id:
return state.filter(item => item.id !== action.id)
Чтобы удалить ключ из объекта по id:
let copy = Object.assign({}, state) // assuming you use Object.assign() polyfill!
delete copy[action.id] // shallowly mutating a shallow copy is fine
return copy
(Бонус) То же самое с предложением оператора object spread оператора:
let { [action.id]: deletedItem, ...rest } = state
return rest
Ответ 2
const remove = (state, bucketId, personId) => state.map(
bucket => bucket.id === bucketId
? { ...bucket, items: bucket.items.filter(person => person.id !== personId) }
: bucket,
);
Использование:
const state = [
{
id: 123,
items: [
{
id: 'abc',
name: 'Kinna',
},
{
id: 'def',
name: 'Meggy',
},
],
},
{
id: 456,
items: [
{
id: 'ghi',
name: 'Ade',
},
{
id: 'jkl',
name: 'Tades',
},
],
},
];
console.log(remove(state, 123, 'abc'));
Ответ 3
Вы можете использовать Underscore reject. Он делает именно то, что вы пытаетесь сделать.
Ответ 4
Если вы решите использовать простой Javascript, самым элегантным способом, который я могу придумать, является использование Array.prototype.reduce
для уменьшения состояния:
var state = [
{ id: 123,
items:[
{ id: 'abc',
name: 'albert'
},
...
]
},
...
]
function filterOut (state) {
return (bucketId, personId) => {
return state.reduce((state, bucket) => {
return state.concat(
(bucketId === bucket.id) ?
Object.assign({}, bucket, {items: bucket.items.filter((person) => person.id !== personId)}) :
bucket
);
}, []);
}
}
var newState = filterOut(state)(123, 'abc');
Ответ 5
Вы также можете использовать метод удаления lodash.
Имейте в виду, что импорт lodash значительно увеличит ваш размер сборки. Держите его под контролем, импортируя только конкретный метод:
import omit from 'lodash/omit';
Если возможно, я предлагаю использовать оператор распространения объектов, как описано в ответить Dan.
Ответ 6
я решил свою проблему таким образом
if(action.type === "REMOVE_FROM_PLAYLIST"){
let copy = Object.assign({}, state)
delete copy.playlist[action.index].songs[action.indexSongs];
return copy;
}
надеюсь, что это поможет любому другому.