Обновление вложенных данных в магазине redux
Каков наилучший/правильный способ обновления вложенного массива данных в хранилище с помощью сокращения?
Мой магазин выглядит следующим образом:
{
items:{
1: {
id: 1,
key: "value",
links: [
{
id: 10001
data: "some more stuff"
},
...
]
},
...
}
}
У меня есть пара асинхронных действий, которые обновляют полный объект items
, но у меня есть другая пара действий, которые я хочу обновить для определенного массива links
.
В настоящее время мой редуктор выглядит так, но я не уверен, что это правильный подход:
switch (action.type) {
case RESOURCE_TYPE_LINK_ADD_SUCCESS:
// TODO: check whether the following is acceptable or should we create a new one?
state.items[action.resourceTypeId].isSourceOf.push(action.resourceTypeLink);
return Object.assign({}, state, {
items: state.items,
});
}
Ответы
Ответ 1
React update()
помощник по неизменности - это удобный способ создания обновленной версии простого старого объекта JavaScript без его изменения.
Вы передаете исходный объект для обновления и объект, описывающий пути к частям, которые необходимо обновить, и изменения, которые необходимо выполнить.
например, если действие имеет свойства id
и link
, и вы хотите нажать link
на массив ссылок в элементе с ключом id
:
var update = require('react/lib/update')
// ...
return update(state, {
items: {
[action.id]: {
links: {$push: action.link}
}
}
})
(Пример использует имя вычисленного свойства ES6 для action.id
)
Ответ 2
Ответ Джонни правильный (никогда не мутируйте состояние, данное вам!), но я хотел добавить еще одно замечание к нему. Если у всех ваших объектов есть идентификаторы, обычно это плохая идея, чтобы сохранить форму состояния вложенной.
Это:
{
items: {
1: {
id: 1,
links: [{
id: 10001
}]
}
}
}
- это форма, которую сложно обновить.
Это не должно быть так! Вы можете вместо этого сохранить его следующим образом:
{
items: {
1: {
id: 1,
links: [10001]
}
},
links: {
10001: {
id: 10001
}
}
}
Это намного проще для обновления, потому что есть только одна каноническая копия любого объекта. Если вам нужно разрешить пользователю "редактировать ссылку", есть только одно место, где необходимо обновить его, и оно полностью не зависит от items
или всего остального, ссылающегося на links
.
Чтобы получить ответы API в такой форме, вы можете использовать normalizr. Как только ваши объекты внутри действий сервера нормализованы, вы можете написать простой редуктор, который объединяет их в текущее состояние:
import merge from 'lodash/object/merge';
function entities(state = { items: {}, links: {} }, action) {
if (action.response && action.response.entities) {
return merge({}, state, action.response.entities);
}
return state;
}
Пожалуйста, см. пример Redux real-world
для демонстрации такого подхода.