州正在返回新州而没有触及州REACT / REDUX

时间:2017-07-04 20:37:52

标签: javascript node.js reactjs redux lodash

在我开始发布代码之前,我将解释我想要发生什么以及发生了什么。

我整天都在努力工作,最后还有一些工作要做。问题是我不知道它为什么会起作用,如果它是最好的方法。 我想要发生的是当用户点击评论上的删除时,我希望从后端的当前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);如何在这里实际更改它?

详细说明我当前的状态如下:

enter image description here

正如你所看到的,我的帖子里面有评论。注释存储在一个数组中,每个注释都是带有text,author.id,author.email和createdAt值的对象。现在正如你在reducecer_post中看到的那样,当关闭动作时,它会关闭DELETE_COMMENTS调度类型并更改状态。

要获得帮助:action.payloadcomment._idaction.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);之类的事情。这一切是如何工作得很好的,不,我不只是复制一些教程并来到这里,并问这只是为了弄清楚其他人是如何做到的。目前我相信魔法,所以解释会很好。

此外,既然我们在这里,这是最好的方法吗?或者在这里有更好的更干净的做事方式。

1 个答案:

答案 0 :(得分:1)

我认为你实际上直接改变了状态,并且在组件仍在更新的意义上以某种方式逃脱它。

让我们遵循逻辑的道路:

  1. deleteComment()中,您引用了this.props.post。该对象可能是通过mapStateToProps从商店中提取的,因此它是商店中的对象引用。
  2. post传递给this.props.deleteComments(post)
  3. deleteComments()发送({type : DELETE_COMMENTS, post})
  4. 在reducer中,您有let newPost = action.post; newPost.comments = newCommentArray。但是,在那时, newPost仍然指向已经处于商店状态的完全相同的对象。所以,你直接改变了它。
  5. 通常,这种突变会导致组件无法重新渲染,因此我只能假设mapState中提取的其他值也正在更新,从而导致重新渲染。 / p>

    正如Redux文档中的Structuring Reducers - Immutable Update Patterns页面所述,let someVariable = anotherVariable没有创建新的对象引用 - 它只是创建了一个指向相同的第二个变量对象引用。正确的不可变更新需要您正在使用的每个嵌套级别的副本,而不仅仅是一个级别。在您的情况下,您是通过_.reject()创建新数组的,但您并未创建post对象的副本。

    所以,最后,你的reducer逻辑是不正确的,你的应用程序有点偶然地工作:)

    <强>更新

    回答有关正确更新的问题:您需要创建post对象的副本并使用新的注释数组更新它,并且您需要复制{{ 1}}对象并使用新的post对象更新它。根据你的其余代码所做的事情,我猜这应该有用:

    state