首页 文章

在Reactjs中是否存在setState()的同步替代

提问于
浏览
22

根据docs中的解释:

setState()不会立即改变this.state,但会创建挂起状态转换 . 调用此方法后访问this.state可能会返回现有值 . 无法保证对setState的调用进行同步操作,并且可以对调用进行批处理以获得性能提升 .

因此, setState() 是异步的,并且无法保证其同步性能 . 是否存在同步的 setState() 替代方案 .

例如

//initial value of cnt:0
this.setState({cnt:this.state.cnt+1})
alert(this.state.cnt);    //alert value:0

由于 alert 值是先前的值,因此使用 setState() 给出 alert value:1 的替代方法是什么 .

Stackoverflow上几乎没有问题类似于这个问题,但没有我能找到正确答案的地方 .

7 回答

  • 1

    正如您从文档中读到的那样,没有同步替代方案,所描述的原因是性能提升 .

    但是我假设您想在更改状态后执行操作,可以通过以下方式实现:

    class MyComponent extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
         x: 1
        };
        
        console.log('initial state', this.state);
      }
      
      updateState = () => {
       console.log('changing state');
        this.setState({
          x: 2
        },() => { console.log('new state', this.state); })
      }
      
      render() {
        return (
          <div>
          <button onClick={this.updateState}>Change state</button>
        </div>
        );
       
      }
    }
    
    ReactDOM.render(
      <MyComponent />,
      document.getElementById("react")
    );
    
    <div id="react"></div>
    <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>
    
  • -2

    不,那里没有 . React将在它认为合适时更新状态,执行诸如将 setState 调用一起进行批处理以提高效率 . 您可能感兴趣的是,您可以将一个函数传递给 setState ,而该函数采用之前的状态,因此您可以选择具有前一个状态的新状态 .

  • 0

    如果这是必需的,我建议在你的setState函数中使用回调(我还建议使用函数setState) .

    状态更新后将调用回调 .

    例如,你的例子就是

    //initial value of cnt:0
    this.setState(
        (state) => ({cnt: state.cnt+1}),
        () => { alert(this.state.cnt)}
    )
    

    根据此处的文档:https://facebook.github.io/react/docs/react-component.html#setstate

    注意:官方文档说,“通常我们建议使用componentDidUpdate()代替这种逻辑 . ”

  • 2

    是的,我们可以使用一种方法来创建同步setState . 但它的表现可能并不像通常那样好 . 例如,我们有

    class MyComponent extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
         data: 0
        };
      }
    
      changeState(){
       console.log('in change state',this.state.data);
       this.state.data = 'new value here'
       this.setState({});
       console.log('in change state after state change',this.state.data);
      }
    
      render() {
        return (
          <div>
          <p>{this.state.data}</p>
          <a onClick={this.changeState}>Change state</a>
        </div>
        );
    
      }
    }
    

    在此示例中,我们首先更改状态,然后渲染我们的组件 .

  • 37

    简短回答你的问题是 - 不,反应没有同步方法 setState .

  • 0

    您可以在返回promise的函数中包装setState,然后将此函数与await关键字一起使用,以使代码等到状态已应用 .

    class MyComponent extends React.Component {
    
        function setStateSynchronous(stateUpdate) {
            return new Promise(resolve => {
                this.setState(stateUpdate, () => resolve());
            });
        }
    
        async function foo() {
            // state.count has value of 0
            await setStateSynchronous(state => ({count: state.count+1}));
            // execution will only resume here once state has been applied
            console.log(this.state.count);  // output will be 1
        }
    }
    

    在foo函数中, await 关键字导致代码执行暂停,直到 setStateSynchronous 返回的promise已经解决,这只有在调用传递回 setState 的回调时才会发生,这只有在应用了状态时才会发生 . 因此,一旦应用了状态更新,执行只会到达console.log调用 .

    async / await的文档:
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

  • 0

    我能够通过将代码包装在_1462908中来欺骗React同步调用 setState . 由于 setTimeout 将东西放在JavaScript事件队列的末尾,我认为React检测到setState在其中,并且知道它不能依赖于批量的 setState 调用(这将被添加到队列的末尾) .

相关问题