在我开始发布代码之前,我将解释我想要发生什么以及发生了什么。
我整天都在努力工作,最后还有一些工作要做。问题是我不知道它为什么会起作用,如果它是最好的方法。
我想要发生的是当用户点击评论上的删除时,我希望从后端的当前post
和前端的状态中删除评论。
更新:我没有真正添加足以显示我在说什么。当用户点击删除按钮时,它将在此处激活此功能:
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}`);
});
}
}
}
然后调用操作:
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);
});
}
}
我想知道:
实际上上面的所有代码都可以工作,所以它更像是一个参考而不是任何东西。我想知道为什么在切换器情况下DELETE_COMMENTS
抓住时的减速器中,如果没有删除注释,图片中下方的当前状态如何变为新状态。我没有明确地编辑状态或更改它,所以return (state);
如何在这里实际更改它?
详细说明我当前的状态如下:
正如你所看到的,我的帖子里面有评论。注释存储在一个数组中,每个注释都是带有text,author.id,author.email和createdAt值的对象。现在正如你在reducecer_post中看到的那样,当关闭动作时,它会关闭DELETE_COMMENTS调度类型并更改状态。
要获得帮助:action.payload
是comment._id
,action.post
是正在查看的当前帖子。
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;
}
}
我知道后端工作得很好,这也很好用。我的问题是它是如何通过放置return (state);
来更新状态的。我没有必要做return _.merge(...state, newPost);
之类的事情。这一切是如何工作得很好的,不,我不只是复制一些教程并来到这里,并问这只是为了弄清楚其他人是如何做到的。目前我相信魔法,所以解释会很好。
此外,既然我们在这里,这是最好的方法吗?或者在这里有更好的更干净的做事方式。
答案 0 :(得分:1)
我认为你实际上直接改变了状态,并且在组件仍在更新的意义上以某种方式逃脱它。
让我们遵循逻辑的道路:
deleteComment()
中,您引用了this.props.post
。该对象可能是通过mapStateToProps
从商店中提取的,因此它是商店中的对象引用。post
传递给this.props.deleteComments(post)
deleteComments()
发送({type : DELETE_COMMENTS, post})
let newPost = action.post; newPost.comments = newCommentArray
。但是,在那时, newPost
仍然指向已经处于商店状态的完全相同的对象。所以,你直接改变了它。通常,这种突变会导致组件无法重新渲染,因此我只能假设mapState
中提取的其他值也正在更新,从而导致重新渲染。 / p>
正如Redux文档中的Structuring Reducers - Immutable Update Patterns页面所述,let someVariable = anotherVariable
没有创建新的对象引用 - 它只是创建了一个指向相同的第二个变量对象引用。正确的不可变更新需要您正在使用的每个嵌套级别的副本,而不仅仅是一个级别。在您的情况下,您是通过_.reject()
创建新数组的,但您并未创建post
对象的副本。
所以,最后,你的reducer逻辑是不正确的,你的应用程序有点偶然地工作:)
<强>更新强>
回答有关正确更新的问题:您需要创建post
对象的副本并使用新的注释数组更新它,并且您需要复制{{ 1}}对象并使用新的post对象更新它。根据你的其余代码所做的事情,我猜这应该有用:
state