Почему мое состояние не обновляется должным образом при создании раздела комментариев? - PullRequest
0 голосов
/ 25 сентября 2019

Я пытаюсь создать раздел комментариев, где 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 голосов
/ 25 сентября 2019

Проблема .

Вы сохраняете author и message в переменной экземпляра (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>
    );
  }
}
0 голосов
/ 25 сентября 2019
this.setState(prevState => ({comments: [...prevState.comments, newComment]}))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...