React-Redux обновляет состояние неизменяемого объекта с вложенным массивом, удаляет элемент из массива

У меня есть следующий объект, из которого я хочу удалить один комментарий.

    msgComments = {
        comments: [
            { comment:"2",
              id:"0b363677-a291-4e5c-8269-b7d760394939",
              postId:"e93863eb-aa62-452d-bf38-5514d72aff39" },
            { comment:"1",
              id:"e88f009e-713d-4748-b8e8-69d79698f072",
              postId:"e93863eb-aa62-452d-bf38-5514d72aff39" }
        ],
    email:"[email protected]",
    id:"e93863eb-aa62-452d-bf38-5514d72aff39",
    post:"test",
    title:"test" 
    }

Создатель действия нажимает на функцию удаления API с помощью commentId:

// DELETE COMMENT FROM POST

export function deleteComment(commentId) {
  return function(dispatch) {
    axios.post(`${API_URL}/datacommentdelete`, {
      commentId
    },{
      headers: { authorization: localStorage.getItem('token') }
    })
      .then(result => {
        dispatch({
          type: DELETE_COMMENT,
          payload: commentId
        });
      })
  }
}

Мой API удаляет комментарий, и я отправляю идентификатор комментария в свой Редьюсер, на данный момент это работает нормально, API работает, а комментарий удаляется. Проблема заключается в обновлении состояния в редюсере. После долгих проб и ошибок в данный момент я пытаюсь это сделать.

case DELETE_COMMENT:
  console.log('State In', state.msgComments);
  const msgCommentsOne = state.msgComments;
  const msgCommentsTwo = state.msgComments;
  const deleteIndexComment = state.msgComments.data.comments
    .findIndex(elem => elem.id === action.payload );
  const newComments = [
    ...msgCommentsTwo.data.comments.slice(0, deleteIndexComment),
    ...msgCommentsTwo.data.comments.slice(deleteIndexComment + 1)
  ];
  msgCommentsOne.data.comments = newComments;
  console.log('State Out', msgCommentsOne);
  return {...state, msgComments: msgCommentsOne};

Оба состояния в И состоянии вывода возвращают один и тот же объект, у которого удален соответствующий комментарий, что меня озадачивает.

Кроме того, компонент не обновляется (когда я обновляю, комментарий исчезает, поскольку делается новый вызов API для возврата обновленного сообщения.

Все остальное вроде работает нормально, проблема похоже в редукторе.

Я прочитал другие сообщения о неизменности, которые были актуальны, и я все еще не могу найти решение. Я также исследовал и нашел библиотеку immutability.js, но прежде чем научиться ее использовать, я хотел найти решение (возможно, трудный путь, но я хочу понять, как это работает!).


person alexi2    schedule 25.07.2016    source источник
comment
И именно поэтому предлагаемый подход к структурированию хранилища Redux заключается в том, чтобы сохранить ваше состояние плоским и нормализованным :) К вашему сведению, в настоящее время я работаю над новым набором страниц для документов Redux, описывающих, как писать логику редуктора и обрабатывать нормализованные данные. является частью этого. Описание задачи находится по адресу github.com/reactjs/redux/issues/1784 и он имеет ссылку на WIP-страницы. Возможно, вам будет интересно их прочитать.   -  person markerikson    schedule 25.07.2016
comment
Да, обходной путь может быть на самом API   -  person alexi2    schedule 25.07.2016


Ответы (2)


Первое рабочее решение

case DELETE_COMMENT:
  const deleteIndexComment = state.msgComments.data.comments
    .findIndex(elem => elem.id === action.payload);

  return {
    ...state, msgComments: {
      data: {
        email: state.msgComments.data.email,
        post: state.msgComments.data.post,
        title: state.msgComments.data.title,
        id: state.msgComments.data.id,
        comments: [
          ...state.msgComments.data.comments.slice(0, deleteIndexComment),
          ...state.msgComments.data.comments.slice(deleteIndexComment + 1)
        ]
      }
    }
  };

Редактировать:

Второе рабочее решение

Я нашел второе, гораздо более краткое решение, приветствуются комментарии:

case DELETE_COMMENT:
  const deleteIndexComment = state.msgComments.data.comments
    .findIndex(elem => elem.id === action.payload);

  return {
    ...state, msgComments: {
      data: {
        ...state.msgComments.data,
        comments: [
          ...state.msgComments.data.comments.slice(0, deleteIndexComment),
          ...state.msgComments.data.comments.slice(deleteIndexComment + 1)
        ]
      }
    }
  };
person alexi2    schedule 25.07.2016

Этот код, по-видимому, напрямую мутирует объект состояния. Вы создали новый массив, в котором отфильтрован удаленный элемент, но затем вы напрямую назначаете новый массив msgCommentsOne.data.comments. Поле data — это то же самое, что уже было в состоянии, так что вы напрямую изменили его. Чтобы правильно обновлять данные без изменений, вам необходимо создать новый массив comments, новый объект data, содержащий комментарии, новый объект msgComments, содержащий данные, и новый объект state, содержащий msgComments. Всю цепочку :)

Часто задаваемые вопросы по Redux содержат немного больше информации по этой теме, по адресу http://redux.js.org/docs/FAQ.html#react-not-rerendering.

У меня есть ряд ссылок на статьи, в которых говорится об неизменном управлении простыми данными Javascript, по адресу https://github.com/markerikson/react-redux-links/blob/master/immutable-data.md . Кроме того, существует множество служебных библиотек, которые могут помочь абстрагировать процесс неизменного выполнения этих вложенных обновлений, которые я перечислил по адресу https://github.com/markerikson/redux-ecosystem-links/blob/master./immutable-data.md.

person markerikson    schedule 25.07.2016