简体   繁体   English

如何使用 componentDidMount 重置状态?

[英]How to reset state with componentDidMount?

I'm a newbie to React and I am working on a quiz.我是 React 的新手,我正在做一个测验。 What I would like to do now is reset the classnames to it's initial state when you get a new question.我现在想做的是在您收到新问题时将类名重置为其初始状态。 I think I want to use componentDidUpdate but not really sure how it works.我想我想使用 componentDidUpdate 但不确定它是如何工作的。

  componentDidUpdate() {
    this.setState({
      classNames: ["", "", "", ""]
    });
  }

Here is the full component code:这是完整的组件代码:

class Answers extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isAnswered: false,
      classNames: ["", "", "", ""]
    };

    this.checkAnswer = this.checkAnswer.bind(this);
  }

  checkAnswer(e) {
    let { isAnswered } = this.props;

    if (!isAnswered) {
      let elem = e.currentTarget;
      let { correct, increaseScore } = this.props;
      let answer = Number(elem.dataset.id);
      let updatedClassNames = this.state.classNames;

      if (answer === correct) {
        updatedClassNames[answer - 1] = "right";
        increaseScore();
      } else {
        updatedClassNames[answer - 1] = "wrong";
      }

      this.setState({
        classNames: updatedClassNames
      });

      this.props.showButton();
    }
  }

  componentDidUpdate() {
    this.setState({
      classNames: ["", "", "", ""]
    });
  }

  render() {
    let { answers } = this.props;
    let { classNames } = this.state;

    return (
      <div id="answers">
        <ul>
          <li onClick={this.checkAnswer} className={classNames[0]} data-id="1">
            <p>{answers[0]}</p>
          </li>
          <li onClick={this.checkAnswer} className={classNames[1]} data-id="2">
            <p>{answers[1]}</p>
          </li>
          <li onClick={this.checkAnswer} className={classNames[2]} data-id="3">
            <p>{answers[2]}</p>
          </li>
          <li onClick={this.checkAnswer} className={classNames[3]} data-id="4">
            <p>{answers[3]}</p>
          </li>
        </ul>
      </div>
    );
  }
}

export default Answers;

Any help is appreciated!任何帮助表示赞赏! And feedback on the whole code project is also much appreciated since I am learning.自从我学习以来,对整个代码项目的反馈也非常感谢。

Below is a link the complete project:以下是完整项目的链接:

https://codesandbox.io/s/another-quiz-mfmop https://codesandbox.io/s/another-quiz-mfmop

There is an easy fix for this (and recommended as a React best practice), if you change the key for the answers, working demo: https://codesandbox.io/s/another-quiz-wgycs对此有一个简单的解决方法(并推荐作为 React 最佳实践),如果您更改答案的key ,工作演示: https : //codesandbox.io/s/another-quiz-wgycs

<Answers
  key={question}    // <-- oh hi
  answers={answers}
  correct={correct}
  ...

Ideally you would use an id , and since most modern data structures have an id, this would make it ideal to use key={question_id} as the key has to be unique:理想情况下,您将使用id ,并且由于大多数现代数据结构都有一个 id,因此使用key={question_id}是理想的,因为键必须是唯一的:

{
    id: 1
    question: 'What does CSS stand for?',
    answers: [...],
    correct: 3
},
{
    id: 2,
     ....
}

If not, you would have to use prevProps :如果没有,您将不得不使用prevProps

componentDidUpdate(prevProps) {
  if (this.props.question !== prevProps.question) {
    this.setState(....)
  }
}

I really recommend the key way, as this will force the creation of a new component, in practice if you need to keep checking for changing props, it can become a bit hard to keep track.我真的推荐key方式,因为这将强制创建一个新组件,在实践中,如果您需要不断检查更改的 props,跟踪可能会变得有点困难。

Remember, ideally there should be an id , because if the question text is the same, it would lead to a nasty hard-to-find bug.请记住,理想情况下应该有一个id ,因为如果问题文本相同,则会导致令人讨厌的难以找到的错误。

Also, instead of saving the classnames, it's better to just save selected as an index and choose the right classname on the render method.此外,与其保存类名,不如将selected保存为索引并在渲染方法上选择正确的类名。

First of all, You have to add a button to reset the classes names and this button will call a function for resetting them like:首先,您必须添加一个按钮来重置类名称,此按钮将调用一个函数来重置它们,例如:


import React from "react";

class Answers extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isAnswered: false,
      classNames: ["", "", "", ""]
    };
  }

  checkAnswer = e => {
    let { isAnswered } = this.props;

    if (!isAnswered) {
      let elem = e.currentTarget;
      let { correct, increaseScore } = this.props;
      let answer = Number(elem.dataset.id);
      let updatedClassNames = this.state.classNames;

      if (answer === correct) {
        updatedClassNames[answer - 1] = "right";
        increaseScore();
      } else {
        updatedClassNames[answer - 1] = "wrong";
      }

      this.setState({
        classNames: updatedClassNames
      });

      this.props.showButton();
    }
  };

  reset = () => {
    this.setState({
      isAnswered: false,
      classNames: ["", "", "", ""]
    });
  };
  render() {
    let { answers } = this.props;
    let { classNames } = this.state;

    return (
      <div id="answers">
        <button onClick={this.reset}>RESET</button>
        <ul>
          <li onClick={this.checkAnswer} className={classNames[0]} data-id="1">
            <p>{answers[0]}</p>
          </li>
          <li onClick={this.checkAnswer} className={classNames[1]} data-id="2">
            <p>{answers[1]}</p>
          </li>
          <li onClick={this.checkAnswer} className={classNames[2]} data-id="3">
            <p>{answers[2]}</p>
          </li>
          <li onClick={this.checkAnswer} className={classNames[3]} data-id="4">
            <p>{answers[3]}</p>
          </li>
        </ul>
      </div>
    );
  }
}

export default Answers;

componentDidUpdate() is invoked immediately after updating occurs. componentDidUpdate()在更新发生后立即调用。 This method is not called for the initial render.初始渲染不会调用此方法。 I have face this kind of scenario recently.我最近遇到了这种情况。 you have to the same code in componentDidUpdate() {} .您必须在componentDidUpdate() {}使用相同的代码。 Here is what I did.这是我所做的。

   componentDidUpdate(prevProps) {
      if (this.props.questions !== prevProps.questions) {
          const shuffledAnswerOptions = this.props.questions.map(question =>
          question.answer_options && 
            this.shuffleArray(question.answer_options)
          );

           this.setState({
              current_question:this.props.questions && 
               this.props.questions[0],
               question_image_url: this.props.questions && 
               this.props.questions[0] && 
             this.props.questions[0].question_image_url,
           answerOptions: shuffledAnswerOptions[0],
         numberOfQuestions: this.props.questions && 
          this.props.questions.length
          });
       }
     }

In your case you prevSate parameter as well.在您的情况下,您prevSate参数。

here is a sample implementation:这是一个示例实现:

componentDidUpdate(prevProps, prevState) {
      if(this.state.assignment !== prevState.assignment){
        document.getElementById(prevState.assignment.id) && document.getElementById(prevState.assignment.id).classList.remove("headactiveperf");
      }
      if(this.state.assessment !== prevState.assessment){
        document.getElementById(prevState.assessment.id) && document.getElementById(prevState.assessment.id).classList.remove("headactiveperf");
      }
      if(this.state.study_group_id !== prevState.study_group_id){
        document.getElementById(prevState.study_group_id) && document.getElementById(prevState.study_group_id).classList.remove("klassactiveperf");
      }
  }

The problem is that if you change state in componentDidUpdate it will trigger another update right away and therefore run componentDidUpdate again and result in an infinite loop.问题是,如果您更改componentDidUpdate状态,它将立即触发另一个更新,因此再次运行componentDidUpdate并导致无限循环。 So you should either move the setState somewhere else, or put it behind a condition.因此,您应该将setState移到其他地方,或者将其置于条件之后。 eg:例如:

componentDidUpdate() {
  if (!this.state.classNames.every(className => className === "") { // Check if there is an item in the array which doesn't match an empty string ("")
    this.setState({ // Only update state if it's necessary
      classNames: ["", "", "", ""]
    });
  }
}

You can find an updated CodeSandbox here您可以在此处找到更新的 CodeSandbox

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM