Подтвердить что ты не робот

Обновление вложенных данных в магазине 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,
      });
  }
4b9b3361

Ответ 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 для демонстрации такого подхода.