1

I have the following object, from which I want to remove one comment.

    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" 
    }

The action creator hits the api delete function with the 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
        });
      })
  }
}

My api deletes the comment and I send the comment id to my Reducer, this is working fine to this point, api works and comment is deleted. The problem is updating the state in the reducer. After much trial and error at the moment I am trying this.

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};

Both state in AND state out return the same object, which has the appropriate comment deleted which I find puzzling.

Also the component is not updating (when I refresh the comment is gone as a new api call is made to return the updated post.

Everything else seems to work fine, the problem seems to be in the reducer.

I have read the other posts on immutability that were relevant and I am still unable to work out a solution. I have also researched and found the immutability.js library but before I learn how to use that I wanted to find a solution (perhaps the hard way, but I want to understand how this works!).

2
  • And this is why the suggested approach to structuring a Redux store is to keep your state flatter and normalized :) FYI, I'm currently working on a new set of pages for the Redux docs describing how to write reducer logic, and handling normalized data is part of that. The task description is at github.com/reactjs/redux/issues/1784 , and it has a link to the WIP pages. You may be interested in reading through them. Commented Jul 25, 2016 at 3:29
  • Yep, work around might be on the api itself Commented Jul 25, 2016 at 3:30

2 Answers 2

2

First working solution

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)
        ]
      }
    }
  };

Edit:

Second working solution

I have found a second far more terse solution, comments welcome:

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)
        ]
      }
    }
  };
Sign up to request clarification or add additional context in comments.

Comments

1

That code appears to be directly mutating the state object. You've created a new array that has the deleted item filtered out, but you're then directly assigning the new array to msgCommentsOne.data.comments. The data field is the same one that was already in the state, so you've directly modified it. To correctly update data immutably, you need to create a new comments array, a new data object containing the comments, a new msgComments object containing the data, and a new state object containing msgComments. All the way up the chain :)

The Redux FAQ does give a bit more information on this topic, at http://redux.js.org/docs/FAQ.html#react-not-rerendering.

I have a number of links to articles talking about managing plain Javascript data immutably, over at https://github.com/markerikson/react-redux-links/blob/master/immutable-data.md . Also, there's a variety of utility libraries that can help abstract the process of doing these nested updates immutably, which I have listed at https://github.com/markerikson/redux-ecosystem-links/blob/master/immutable-data.md.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.