状态正在返回新状态而未触及状态REACT/REDUX [英] State is returning new state without touching the state REACT/REDUX

查看:68
本文介绍了状态正在返回新状态而未触及状态REACT/REDUX的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我开始发布代码之前,我将解释我想发生的事情和正在发生的事情.

Before I start posting the code I will explain what I want to happen and what is happening.

我整天都在工作,终于有了工作.问题是我不知道它为什么起作用以及这是否是最好的方法.我想发生的是,当用户单击评论的删除时,我希望从后端的当前 post 和前端的状态中删除该评论.

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

然后调用该操作:

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(状态); 实际如何在此处更改状态?

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:

如您所见,我有一个内部带有评论的帖子.注释存储在一个数组中,每个注释都是带有文本,author.id,author.email和createdAt值的对象.现在,如您在reducer_post中所看到的,当触发该操作时,它将发送DELETE_COMMENTS调度类型,并更改状态.

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.

获得帮助: action.payload comment._id ,而 action.post 是当前正在查看的帖子.

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

我知道后端工作得很好,这也很好.我的问题是,如何仅通过输入 return(state); 来更新状态.我不必做 return _.merge(... state,newPost); 之类的事情.所有这些如何工作得很好,不,我不只是复制一些教程并来到这里问这个只是为了弄清楚其他人是如何做到的.目前,我相信魔术,因此不失为一个解释.

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.

推荐答案

我认为您实际上是在直接改变状态,并且从某种意义上说,在组件仍在更新的状态下,它可以摆脱.

I think you're actually directly mutating the state, and somehow getting away with it in the sense that the component is still updating.

让我们遵循逻辑:

  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 仍指向已经处于存储状态的完全相同的对象.因此,您已经直接对其进行了变异.
  1. In deleteComment(), you reference this.props.post. That object is presumably extracted from the store via mapStateToProps, so it's the object reference in the store.
  2. post gets passed to this.props.deleteComments(post)
  3. deleteComments() dispatches ({type : DELETE_COMMENTS, post})
  4. In the reducer, you have let newPost = action.post; newPost.comments = newCommentArray. But, at that point, newPost still points to the exact same object that's already in the store state. So, you've directly mutated it.

通常,这种突变会导致您的组件无法重新呈现,因此我只能假设从 mapState 中提取的其他一些值也正在正确更新,从而导致重新渲染.

Normally, this kind of mutation would result in your component not re-rendering, so I can only assume that some other value extracted in mapState is also getting updated properly, and thus causing a re-render.

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

As discussed in the Structuring Reducers - Immutable Update Patterns page in the Redux docs, let someVariable = anotherVariable doesn't create a new object reference - it merely creates a second variable that points to the same object reference. Proper immutable updates require copies of every level of nesting that you're working with, not just the one level. In your case, you're creating a new array via _.reject(), but you're not creating a copy of the post object.

因此,最后,您的reducer逻辑不正确,并且您的应用程序有点偶然地起作用:)

So, in the end, your reducer logic is incorrect, and your application is sorta kinda working by accident :)

更新

回答有关适当更新的问题:您需要创建 post 对象的副本,并使用新的注释数组对其进行更新,然后您需要复制 state 对象,并使用新的post对象对其进行更新.根据您其余代码的工作,我猜这应该可行:

Responding to your question about a proper update: you need to create a copy of the post object and update it with the new comments array, and you need to copy the state object and update it with the new post object. Based off what the rest of your code does, my guess is this should work:

case DELETE_COMMENTS:
     const newCommentArray = _.reject(action.post.comments, {'_id': action.payload});

     const newState = {
         ...state,
         [action.post.id] : {
             ...action.post,
             comments : newCommentArray
         }
     };

     return newState;

这篇关于状态正在返回新状态而未触及状态REACT/REDUX的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆