【问题标题】:React: Component state not updating scorekeeper or counter反应:组件状态不更新记分员或计数器
【发布时间】:2018-05-28 11:50:55
【问题描述】:

每当我在四个选项中单击正确或错误的“答案”div 时,我都会尝试更新我的组件状态,以更新记分员和计数器。但是,当我控制台注销记分员和计数器值时,无论我回答了多少问题,我总是得到 0。为什么会发生这种情况,如何更新这两个组件状态?

这是我的代码:

export default class QuestionCard extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            scorekeeper: 0, 
            counter: 0,
            hideDiv: false
        }

        this.handleClick = this.handleClick.bind(this);
        this.handleClickCont = this.handleClickCont.bind(this);
    }

    handleClick(choice) {
        if(this.state.counter === 4) {
            return console.log('we have four')
        }

        this.handleClickCont(choice)
    }

    handleClickCont(choice) {
        if(choice === this.props.answer) {
            this.setState({scorekeeper: this.state.scorekeeper + 1});
            this.setState({counter: this.state.counter + 1});
            console.log('scorekeeper ' + this.state.scorekeeper)
            console.log('counter ' + this.state.counter)
            return this.setState({hideDiv: !this.state.hideDiv});
        } 

        this.setState({scorekeeper: this.state.scorekeeper - 1});
        this.setState({counter: this.state.counter + 1});
        console.log('scorekeeper ' + this.state.scorekeeper);
        console.log(this.state.counter)
        this.setState({hideDiv: !this.state.hideDiv});
    }

    render() {
        return (
            <div style={{margin: '20px', display: this.state.hideDiv ? 'none' : 'block'}}>
                <div>
                    {this.props.question}
                </div>

                <div style={{
                        margin: '20px', 
                        width: '500px', 
                        display: 'flex', 
                        justifyContent: 'space-around',
                        display: this.state.hideDiv ? 'none' : 'block'
                      }}>
                    <div onClick={() => this.handleClick(this.props.choice1)}>
                        {this.props.choice1}
                    </div>
                    <div onClick={() => this.handleClick(this.props.choice2)}>
                        {this.props.choice2}
                    </div>
                    <div onClick={() => this.handleClick(this.props.choice3)}>
                        {this.props.choice3}
                    </div>
                    <div onClick={() => this.handleClick(this.props.choice4)}>
                        {this.props.choice4}
                    </div>
                </div>
            </div>
        );
    }
}

【问题讨论】:

  • 你试过this.setState(prevState =&gt; {counter: prevState.counter + 1});。这样您就不会丢失先前状态的当前值。

标签: reactjs function if-statement components state


【解决方案1】:

设置状态是异步的,因此 react 可以通过批量调用 setState 来做一些性能优化。因此,依赖于先前状态值的状态更改(即用于递增计数器)您应该使用setState 的函数版本 https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

您在调用 setState 后立即记录,但由于它是异步的,因此您正在记录的状态可能 实际上 还没有被 react 设置。您可以改为将其记录在回调中,保证在状态实际上已在表面下更新后运行

顺便说一句,如果答案正确与否,您的代码的作用完全相同,只是它增加而不是减少分数,因此我们可以将其稍微干燥到单个 setState 中,并带有条件增量值

handleClickCont(choice) {
  this.setState(prevState => ({
      scorekeeper: prevState.scorekeeper + (choice === this.props.answer ? 1 : -1),
      counter: prevState.counter + 1,
      hideDiv: !prevState.hideDiv
    }),
    () => { // callback, guaranteed to have done your updates by this point
      console.log('scorekeeper ' + this.state.scorekeeper)
      console.log('counter ' + this.state.counter)
    }
  )
}

【讨论】:

  • 您好,谢谢您的回复。这对我的问题是一个非常有用的解释:)。但是,我用您在此处给出的代码替换了我原来的 handleClickCont 函数,当我第一次回答问题时,状态的记分员和计数器部分会正确更新。但是,第二次及以后的时间将控制台记录 1 保持在两个状态的值...
  • 所以这听起来像是一个不同的问题,其中 QuestionCard 是一个不同的实例,可能是从被卸下然后用不同的问题道具重新安装。在这种情况下,状态计数器将再次从 0 开始,因此您最多只能达到 1。必须看看是什么控制了这些问题以及呈现了什么&lt;QuestionCard /&gt; 才能确定原因
  • 此组件中没有任何内容可以在回答时更改卡片中的问题,实际上您在回答时将其完全隐藏,这让我认为您只是有 4 个并排单独的 QuestionCard 实例,在这种情况下他们对彼此的状态一无所知。状态包含在单个实例中
  • 这个分数/计数器状态应该在父级中,它知道所有问题卡,问题卡本身具有触发状态设置的onAnswered(correct: boolean): void 属性
  • 是的,没错,我有 4 个并排单独的 QuestionCard 实例。我将状态的分数和计数器部分移动到父组件,现在它工作得很好。非常感谢!!
【解决方案2】:

记住 this.setState 就像 return 语句。可能不会执行 setstate 之后的所有语句。一旦你设置了组件的渲染方法就会被调用,除非你指定不渲染。更进一步的语句可能不会被执行。

handleClickCont(choice) {
    if(choice === this.props.answer) {
        this.setState({scorekeeper: this.state.scorekeeper + 1,counter: this.state.counter + 1,hideDiv: !this.state.hideDiv});
    } else{

    this.setState({scorekeeper: this.state.scorekeeper - 1,counter: this.state.counter + 1,hideDiv: !this.state.hideDiv});
    }

}

你也不能返回 this.setState。调用 setState 时也不总是执行它。 react 可能会对其进行批处理并稍后执行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-19
    • 2020-03-29
    • 1970-01-01
    • 2015-05-21
    • 2020-02-02
    • 2021-10-22
    • 2017-09-10
    • 2021-05-19
    相关资源
    最近更新 更多