在反应类组件中,为啥在按钮单击的第一个实例中状态没有改变?但在第二种情况下,它会更新吗?

Posted

技术标签:

【中文标题】在反应类组件中,为啥在按钮单击的第一个实例中状态没有改变?但在第二种情况下,它会更新吗?【英文标题】:In react class component why is the state not being changed in the first instance of button click? But in the second instance it gets updated?在反应类组件中,为什么在按钮单击的第一个实例中状态没有改变?但在第二种情况下,它会更新吗? 【发布时间】:2019-07-26 08:02:12 【问题描述】:

在下面的代码中,当我第一次单击按钮时,即使使用 setState() 更改了状态,它也会打印原始状态值。但是当我第二次单击该按钮时,它会打印新的状态值

import React, Component from 'react';

class App extends Component
  state = 
    name:'Aneesh',
    age: '30'
  

  handleClick= (event)=>
    //this prints the original state
    console.log(this.state);
    this.setState(
      name:'Rayancha'
    )
    //This prints the original state in the first click and prints the new state after the second click
    console.log(this.state);
  




  render()
    return (
      <div>
        <h1>I am app component</h1>
        <p>My name is: this.state.name and my Age is this.state.age</p>
        <button onClick=this.handleClick>Click Me</button>
      </div>
    )
  


export default App;

【问题讨论】:

setState 是一个异步函数,详见documentation 感谢接受 algoboy :)!希望我的解决方案对您有用。 【参考方案1】:

setState 以异步方式工作。这意味着在调用 setState 之后,this.state 变量不会立即更改。因此,如果您想在状态变量上设置状态后立即执行操作,然后返回结果,请使用回调。 尝试使用回调函数如下:

handleClick= (event)=>
    //this prints the original state
    console.log(this.state);
    this.setState(
      name:'Rayancha'
    , () => console.log(this.state))
  

这将确保在返回setState 时调用console.log。

【讨论】:

此外,如果您可以使用 async/await,您可以将箭头函数标记为 asyncawait setState。后续代码只会在状态更新后运行。 @Phillip 这不是真的,因为setState 不会返回Promise(你不能await 它)。【参考方案2】:

您的代码实际上正在正确更新。问题是在调用this.setState() 之后直接执行console.log(this.state)。你看,this.setState() 是异步的,这意味着当你调用它时,没有什么可以阻止在它之后编写的代码立即运行。简单地说,console.log() 在状态更新完成之前运行。

作为您的状态实际更新的证据,您可以在render 中运行console.log()。因为,每次更新状态时组件都会re-render,因此您将打印新的状态值。

import React, Component from 'react';

class App extends Component
  state = 
    name:'Aneesh',
    age: '30'
  

  handleClick= (event)=>
    //this prints the original state
    console.log(this.state);
    this.setState(
      name:'Rayancha'
    )
    //This prints the original state in the first click and prints the new state after the second click
    console.log(this.state);
  

  render()
    console.log(this.state.name)
    return (
      <div>
        <h1>I am app component</h1>
        <p>My name is: this.state.name and my Age is this.state.age</p>
        <button onClick=this.handleClick>Click Me</button>
      </div>
    )
  


export default App;

【讨论】:

【参考方案3】:

你做得对,控制台会在你的状态设置之前执行,所以如果你把控制台放在渲染中,你可以看到你的状态已经正确改变了。

要解决此问题,您必须向 setState 传递一个回调,该回调仅在您的 setState 执行后才会执行。

如果确实需要,请使用回调,如果您想在渲染下使用状态,则必须避免这种情况,因为在多次渲染的情况下它会使您的应用程序变慢。

handleClick= (event)=>
    this.setState(
      name:'Rayancha'
    , () => console.log(this.state))
  

请查看seState Api https://reactjs.org/docs/react-component.html#setstate的官方文档

【讨论】:

以上是关于在反应类组件中,为啥在按钮单击的第一个实例中状态没有改变?但在第二种情况下,它会更新吗?的主要内容,如果未能解决你的问题,请参考以下文章

Angular - 从特定组件实例获取数据,以便能够通过单击按钮与之交互

使用对话框中的状态按钮或 Material UI 中的警报来反应内存泄漏警告

如何通过单击类组件中的按钮来进行路由?

为啥反应显示组件更新但控制台不更新?

谁能解释为啥这适用于类组件而不是功能组件?

为啥渲染方法在类组件中运行两次而没有包含任何状态?