Обновить вложенный объект в массиве в хранилище с избыточностью - PullRequest
1 голос
/ 30 апреля 2019

Так что я изо всех сил пытался найти лучшую практику в этом, меняя магазин, не изменяя магазин напрямую. Особенно когда оно вложено.

Я видел несколько замечательных статей по этому поводу, но я все еще не могу понять, как добиться этого идеально в моем сценарии. (https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns)

В моем случае у меня есть proposals хранилище с records, и каждая запись (proposal) содержит checklist, который представляет собой массив, который выглядит следующим образом:

checklist: [
    {
      label: 'lease_sign',
      done: false
    }
],

Я хочу изменить done на true. Теперь у меня есть это действие, запускаемое моим WebSocket:

case CHECK_TODO_ITEM: {
    const { data } = action;

    // find match record
    const proposal = _.find(state.records, ['uuid', data.proposal]);
    // find match check
    const check = _.find(proposal.checklist, ['label', data.item]);
    // change check to true
    check.done = true;

    // find index of propsal in the current state
    const index = _.findIndex(state.records, (p) => p.uuid === data.proposal);

    // re-asign state
    return _.assign({}, state, {
        records: _.assign({}, state.records, {
            [index]: proposal,
        }),
    });
}

Я также пытался с:

return {
    ...state,
        records: {
            ...state.records,
            [index]: {
                ...state.records[index],
                checklist,
            }
        }
    }
};

Но это все еще мутирует состояние вне курса. Я не могу понять, каков идеальный способ сделать это.

Если бы кто-то мог мне помочь, это было бы здорово!

Ответы [ 3 ]

0 голосов
/ 30 апреля 2019

Просто используйте map, как показано ниже, и оператор распространения для объекта. И map, и ... являются неизменяемыми операциями.

const checklist = [
  { id: 1, done: false },
  { id: 2, done: false },
  { id: 3, done: false }
]

const setDone = id => checklist.map(item => (
  id === item.id ? {...item, done: true } : item
))

console.log(setDone(2));

Для элементов контрольного списка используйте динамически генерируемый уникальный идентификатор и обратитесь к соответствующему элементу состояния с этим идентификатором при переключении.

0 голосов
/ 30 апреля 2019

Объектам присваивается ссылка в ECMAScript, а не значение .

Используя метод find подчеркивания, ваши переменные proposal и check будут по-прежнему ссылаться на объекты в хранилище de Redux, которые вы затем изменяете напрямую. То, что вы хотите сделать, это «клонировать» состояние или часть состояния, в котором вы нуждаетесь, в тот момент, когда ваше действие вызывает редуктор. Существует несколько способов достижения клона:

  • оператор распространения: newState = {...state}
  • newState = JSON.parse(JSON.stringify(state))
  • с использованием lodash (поскольку вы уже используете его): newState = _.cloneDeep(state)

Это новое состояние может быть затем изменено и впоследствии установлено в хранилище.

0 голосов
/ 30 апреля 2019

Для меня лучшая библиотека для обновления неизменяемого состояния - immutability-helper.

С этим вы можете сделать что-то вроде этого (IDK, если это работает, но у вас есть идея):

case CHECK_TODO_ITEM: {
  const index = 8; // random record index
  const index2 = 3; // random item index
  return update(state, {
    records: {      
      [index]: {
        checklist: {
          [index2]: {
            $merge: {
              done: true,
            },
          },
        },
      },
    },
  });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...