反应:组件状态不更新记分员或计数器
Posted
技术标签:
【中文标题】反应:组件状态不更新记分员或计数器【英文标题】: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 => counter: prevState.counter + 1);
。这样您就不会丢失先前状态的当前值。
【参考方案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。必须看看是什么控制了这些问题以及呈现了什么<QuestionCard />
才能确定原因
此组件中没有任何内容可以在回答时更改卡片中的问题,实际上您在回答时将其完全隐藏,这让我认为您只是有 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 可能会对其进行批处理并稍后执行。
【讨论】:
以上是关于反应:组件状态不更新记分员或计数器的主要内容,如果未能解决你的问题,请参考以下文章
如何使用我的反应应用程序中的 useState 钩子给出的 setState 方法增加状态对象的选定索引的计数