创建评论部分时,为什么我的状态没有按预期更新?

时间:2019-09-25 14:43:18

标签: javascript reactjs state

我正在尝试创建评论部分,其中this.state会存储每次提交新评论时通过将旧状态与新状态组合而做出的所有评论。但是,我在我的应用程序中得到了非常奇怪的行为,我无法解释。在第一个评论提交时,该评论通过调用父函数commentForm的回调从commentSection发送到其父handleCommentSubmit,以更新我的comments状态。一切都正确呈现。但是,一旦提交第二条评论,就会进行相同的过程;状态已更新,但不包含先前的第一条评论。在此状态更新之后,新状态将发送到commentList以呈现注释。在这种情况下,奇怪的是,传递给它的道具this.state.comments现在包含一个数组,该数组包含第二个注释的2个(请参见屏幕快照的底部)。这导致我的评论部分现在显示用户2的评论两次,而不显示用户1的评论。有人知道为什么会这样吗?

这是相关代码:

父母:

class CommentsSection extends React.Component{

    constructor(props){
        super(props)
        this.state={comments:[], loading:false}

    }

    componentDidMount(){

    }


    handleCommentSubmit = (newComment) =>{


        var comments = this.state.comments;
        var newComments = comments.concat([newComment]);
        this.setState({comments: newComments},console.log('The current state is now',this.state.comments));
        //comment is object with author and message. Add new comment to old comments
        //this.setState({comments:[...this.state.comments,newComment]},console.log(this.state, 'state updated'))

    }
    //Comments are create in comment form, passed up then sent down through commentList to individual comment rendering inside comment.js
// comment form oncommentsubmit running everytime it renders, not only on submital
    render(){
        const loadingSpin = this.state.loading ? "App-logo Spin" : "App-logo";
        return(
            <div>
                <span><h4> Comments </h4></span>
                <div className="ui grid"> 


                    <div className = "right floated eight wide column" >
                        <CommentList comments={this.state.comments}/> 
                    </div>
                    <div className="left floated eight wide column">

                        <CommentForm onCommentSubmit={this.handleCommentSubmit}/>

                    </div>
                 </div>
             </div>

        )

    }
}

export default CommentsSection

孩子:


function CommentList ({comments}){

    //need to map over array of comments to format correctly
    console.log('This is what is passed as props to CommentList', comments)
    comments = comments.map((comments)=>{return <Comment key = {comments.message} message={comments.message} author={comments.author} />})

    return(<div>{comments}</div>)
}



export default CommentList

class CommentForm extends React.Component{

    constructor(props){
        super(props)


        this.comment={author:'', message:''}
    }


    handleSubmit= (e)=>{
        e.preventDefault()
        var authorVal = this.comment.author;
        var textVal = this.comment.message;
        //this stops any comment submittal if anything missing
        if (!textVal || !authorVal) {
         return;
        }
        this.props.onCommentSubmit(this.comment);
        //reset form values
        e.target[0].value = '';
        e.target[1].value = '';

    }


    handleFormChange= (e)=>{
        e.preventDefault()
        if(e.target.name==='author'){
            var author = e.target.value.trim();
            this.comment.author = author
        }else if(e.target.name==='message'){
            var message = e.target.value.trim();
            this.comment.message = message
        }
    }

    render() {
    return (

        <form className = "ui form" method="post" onChange={(e)=>{this.handleFormChange(e)}} onSubmit={(e)=>{this.handleSubmit(e)}}>
          <div className="form-group">
            <input
              className="form-control"
              placeholder="user..."
              name="author"
              type="text"
            />
          </div>

          <div className="form-group">
            <textarea
              className="form-control"
              placeholder="comment..."
              name="message"        
            />
          </div>



          <div className="form-group">
            <button disabled={null} className="btn btn-primary">
              Comment &#10148;
            </button>
          </div>
        </form>

    );
  }
}

comment section screenshot Console.log

2 个答案:

答案 0 :(得分:0)

this.setState(prevState => ({comments: [...prevState.comments, newComment]}))

答案 1 :(得分:0)

问题

您正在将authormessage存储在this.comment组件的实例变量(<CommentForm />)上。this.comment甚至在重新存储后仍保持相同的存储位置-渲染。因此,即使在重新渲染之后,它也是同一个对象。您只是覆盖该对象的属性。而您的父状态是一个注释数组,其中每个元素只是指向同一this.comment对象的指针,该对象每次都会被覆盖。

查看链接,继续添加注释以查看父组件状态发生了什么 https://stackblitz.com/edit/react-cubmcf

解决方案

修改handleSubmit就像这样。

handleCommentSubmit = newComment => {
  var comments = this.state.comments;
  // var newComments = comments.concat([newComment]);
 this.setState({
   comments: [...comments, newComment]
 });
 
};

更新注释表单以使用状态而不是实例变量。

所做的更改

  1. 直接删除了更新dom元素。
  2. 用于输入字段的受控组件
  3. 一些常规重构。

class CommentForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = { author: "", message: "" };
  }

  handleSubmit = e => {
    e.preventDefault();
    const {author, message} = this.state;
    //this stops any comment submittal if anything missing
    if (!author || !message) {
      return;
    }
    this.props.onCommentSubmit({ author, message });
    this.setState({author: "",  message : ""})
  };

  handleFormChange = e => {
    e.preventDefault();
    this.setState({[e.target.name]: e.target.value});    
  };

  render() {
      const {author, message} =  this.state;
    return (
      <form
        className="ui form"
        method="post"
        onChange={e => {
          this.handleFormChange(e);
        }}
        onSubmit={e => {
          this.handleSubmit(e);
        }}
      >
        <div className="form-group">
          <input
            className="form-control"
            placeholder="user..."
            name="author"
            type="text"
            value = {author}
          />
        </div>

        <div className="form-group">
          <textarea
            className="form-control"
            placeholder="comment..."
            name="message"
            value={message}
          />
        </div>

        <div className="form-group">
          <button disabled={null} className="btn btn-primary">
            Comment &#10148;
          </button>
        </div>
      </form>
    );
  }
}