Before I start posting the code I will explain what I want to happen and what is happening.
I have been working with this all day and finally got something to work. The problem is that I have no clue why it works and if it's the best way to do it.
What I want to happen is when a User clicks delete on a comment I want the comment to be delete from the current post
on the back end and from the state on the front end.
UPDATE: I did not really add enough to show what I was talking about. When a user clicks the delete button it will fire off this function here:
deleteComment(comment) {
const {id} = this.props.match.params;
const {user, post, auth} = this.props;
if(!user) {
return (<div></div>);
}
if(auth) {
if(user._id === comment.author.id){
this.props.deleteComments(post, comment._id, () => {
this.props.history.push(`/posts/${post._id}`);
});
}
}
}
which then calls the action:
export function deleteComments(post, comment_id, cb) {
return function(dispatch) {
axios.delete(`${ROOT_URL}/${post._id}/comments/${comment_id}`)
.then(() => {
dispatch({
type: DELETE_COMMENTS,
payload: comment_id,
post: post
});
})
.then(() => cb())
.catch((error) => {
console.log(error);
});
}
}
What I am wondering:
Really all the code above works so it is more of a reference than anything. I am wondering why in the reducer when DELETE_COMMENTS
is caught by the switch case how the current state which is below in the picture is changed to a new state without the comment I deleted. I don't explicitly ever edit the state or change it so how does return (state);
actually change it here?
To elaborate more my current state looks as so:
As you can see I have a Post with comments inside of it. The comments are stored inside an array and each of them are objects with text, author.id, author.email, and createdAt values. Now as you can see in the reducer_post when the action is fired off it sends the DELETE_COMMENTS dispatch type off and the state is changed.
For help: action.payload
is the comment._id
, and action.post
is the current post that is being viewed.
import {
GET_ALL_POSTS,
GET_POST,
CREATE_POST,
DELETE_POST,
UPDATE_POST,
DELETE_COMMENTS
} from '../actions/types';
import _ from 'lodash';
export default function(state = {}, action) {
switch(action.type) {
case GET_ALL_POSTS:
return _.mapKeys(action.payload.data, '_id');
break;
case GET_POST:
return {...state, [action.payload.data._id]: action.payload.data};
break;
case DELETE_POST:
return _.omit(state, action.payload);
break;
case DELETE_COMMENTS:
let newCommentArray = _.reject(action.post.comments, {'_id': action.payload});
let newPost = action.post;
newPost.comments = newCommentArray;
return (state);
case UPDATE_POST:
let updates = {[action.payload.data._id]: action.payload.data};
return _.merge(...state, updates);
break;
default:
return state;
break;
}
}
I know the back-end works just fine and this also works just fine. My question is how does it update the state with me just putting return (state);
. I did not have to do something like return _.merge(...state, newPost);
or something like that. How is all of this working just fine, and no I did not just copy some tutorial and come on here and ask this just to figure out how someone else did it. At the moment I believe in magic so it would be nice for an explanation.
Also since we are here, is this the best way to do it? Or is there a better more clean way of doing things here.