【问题标题】:Why calling setState method doesn't mutate the state immediately?为什么调用 setState 方法不会立即改变状态?
【发布时间】:2018-08-17 03:51:24
【问题描述】:

好的,我会尽快解决这个问题,因为它应该很容易解决...

我读过很多类似的问题,答案似乎很明显。我一开始就不需要查找任何东西!但是...我遇到了一个错误,我无法理解如何解决或为什么会发生。

如下:

class NightlifeTypes extends Component {
constructor(props) {
    super(props);

    this.state = {
        barClubLounge: false,
        seeTheTown: true,
        eventsEntertainment: true,
        familyFriendlyOnly: false
    }
    this.handleOnChange = this.handleOnChange.bind(this);
}

handleOnChange = (event) => {   
    if(event.target.className == "barClubLounge") {
        this.setState({barClubLounge: event.target.checked});
        console.log(event.target.checked)
        console.log(this.state.barClubLounge)
    }
}

render() {
    return (
        <input className="barClubLounge" type='checkbox' onChange={this.handleOnChange} checked={this.state.barClubLounge}/>
    )
}

更多的代码围绕着这个,但这是我的问题所在。应该工作吧?

我也试过这个:

handleOnChange = (event) => {   
if(event.target.className == "barClubLounge") {
    this.setState({barClubLounge: !this.state.barClubLounge});
    console.log(event.target.checked)
    console.log(this.state.barClubLounge)
}

所以我有这两个console.log(),两者应该是一样的。我实际上将状态设置为与上面一行中的event.target.checked 相同!

但它总是返回应有的反面。

当我使用!this.state.barClubLounge 时也是如此;如果它开始为假,那么在我第一次点击时它仍然是假的,即使复选框是否被选中是基于状态的!!

这是一个疯狂的悖论,我不知道发生了什么,请帮忙!

【问题讨论】:

    标签: javascript html reactjs event-handling


    【解决方案1】:

    原因是 setState 是异步的,您不能指望更新后的 state 值就在 setState 之后,如果要检查该值,请使用 callback 方法。将方法作为回调传递,该方法将在 setState 完成其任务后执行。

    为什么 setState 是异步的?

    这是因为setState 改变了state 并导致重新渲染。这可能是一项昂贵的操作,并且将其设置为synchronous 可能会使浏览器无响应。 因此,setState 调用是 asynchronous 以及批处理以获得更好的 UI 体验和性能。

    来自Doc

    setState() 不会立即改变 this.state 而是创建一个 等待状态转换。调用 this 后访问 this.state 方法可能会返回现有值。没有 保证对 setState 的调用和调用的同步操作可能 进行批处理以获得性能提升。

    使用带有 setState 的回调方法:

    要在setState 之后检查更新的state 值,请使用如下回调方法:

    setState({ key: value }, () => {
         console.log('updated state value', this.state.key)
    })
    

    检查一下:

    class NightlifeTypes extends React.Component {
       constructor(props) {
          super(props);
    
          this.state = {
             barClubLounge: false,
             seeTheTown: true,
             eventsEntertainment: true,
             familyFriendlyOnly: false
          }
       }
    
       handleOnChange = (event) => {  // Arrow function binds `this`
          let value = event.target.checked;
    
          if(event.target.className == "barClubLounge") {
    
             this.setState({ barClubLounge: value}, () => {  //here
                 console.log(value);
                 console.log(this.state.barClubLounge);
                 //both will print same value
             });        
    
          }
       }
    
       render() {
          return (
              <input className="barClubLounge" type='checkbox' onChange={this.handleOnChange} checked={this.state.barClubLounge}/>
          )
       }
    }
    
    ReactDOM.render(<NightlifeTypes/>, document.getElementById('app'))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    
    <div id='app'/>

    【讨论】:

      【解决方案2】:

      因为 setState 是一个异步函数。这意味着在调用 setState 后状态变量不会立即改变。因此,如果您想在更改状态后立即执行其他操作,您应该在 setState 更新函数中使用 setstate 的回调方法。

      handleOnChange = (event) => { 
           let inputState = event.target.checked;
            if(event.target.className == "barClubLounge") {
               this.setState({ barClubLounge: inputState}, () => {  //here
                   console.log(this.state.barClubLounge);
                   //here you can call other functions which use this state 
                   variable //
               });        
            }
         }
      

      【讨论】:

        【解决方案3】:

        出于性能考虑,这是设计使然。 React 中的 setState 是一个保证重新渲染组件的函数,这是一个代价高昂的 CPU 进程。因此,它的设计者希望通过将多个渲染动作集中到一个中来进行优化,因此 setState 是异步的。

        【讨论】:

          猜你喜欢
          • 2015-08-27
          • 1970-01-01
          • 2018-08-05
          相关资源
          最近更新 更多