【问题标题】:setState being called multiple times after await等待后多次调用 setState
【发布时间】:2019-02-27 17:20:25
【问题描述】:

我在Codepen写了一个测试用例

单击按钮运行测试,然后从浏览器控制台查看结果。

从控制台日志可以看到,即使我多次调用setState之前 await,它也只会更新组件一次。

但是如果我多次调用setState之后 await,它也会多次更新组件。

知道为什么会这样吗?

代码:

/*
 * A simple React component
 */
class Application extends React.Component {

  state = {
    value: 0
  }

  onClickHandler = (e) => {
    this.runAsyncFunc();
  }

  runAsyncFunc = async() => {
    console.log('BEFORE AWAIT');
    this.setState({ value: 1 });
    this.setState({ value: 1 });
    this.setState({ value: 1 });

    await setTimeout(()=>{}, 2000);

    console.log('AFTER AWAIT');
    this.setState({ value: 1 });
    this.setState({ value: 1 });
    this.setState({ value: 1 });
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('updated');
  }

  render() {
    return <div>
      <p>{this.state.value}</p>
      <button onClick={this.onClickHandler}>RUN TEST</button>
      <p>Please check from Browser Console's Log</p>
    </div>;
  }
}

/*
 * Render the above component into the div#app
 */
React.render(<Application />, document.getElementById('app'));

【问题讨论】:

  • setTimeout 不返回可以等待的承诺。
  • stackoverflow.com/a/48731782/2630817 这可能会有所帮助
  • 另外,setState 本身是异步的,如果可以的话,React 会展平前三个调用。
  • @remix23 我知道 setState 是一个异步调用,但是为什么在 await 之后每次调用 setState 都会触发它?

标签: javascript reactjs


【解决方案1】:

这是因为this answer states React 尝试批量处理setState 调用并尽可能一起处理它们。但异步计算并非如此,因为 React(以及一般任何人)无法预测和重现 setState 的异步调用顺序。

因此,在您的情况下,它会退回到仅更新状态 3 次。

【讨论】:

    【解决方案2】:

    您可以从 React.Component 生命周期文档 (https://reactjs.org/docs/react-component.html) 获得此答案

    componentDidUpdate() is invoked immediately after updating occurs. This method is not called for the initial render.

    使用此方法shouldComponentUpdate()。如果没有理由应用新的渲染,此方法允许您的组件退出更新生命周期。开箱即用, shouldComponentUpdate() 是一个返回 true 的无操作。这意味着每次我们在组件中启动更新时,我们都会重新渲染。

    我添加更多代码

      shouldComponentUpdate = function(nextProps, nextState) {
        return nextState.value !== this.state.value;
      }
    
      // Change value will set after await
      runAsyncFunc = async() => {
        console.log('BEFORE AWAIT');
        this.setState({ value: 1 });
        this.setState({ value: 1 });
        this.setState({ value: 1 });
    
        await setTimeout(()=>{}, 2000);
    
        console.log('AFTER AWAIT');
        this.setState({ value: 2 });
        this.setState({ value: 2 });
        this.setState({ value: 2 });
      }
    

    查看我的Codepen

    所以如果你想防止不必要的渲染自定义方法shouldComponentUpdate

    【讨论】:

    • 我并没有试图阻止不必要的渲染。我只想知道为什么在 await 之后每当调用 setState 时它都会触发 componentDidUpdate()
    猜你喜欢
    • 2019-09-03
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    • 2019-10-21
    • 2018-08-19
    • 2019-05-03
    • 1970-01-01
    • 2016-03-06
    相关资源
    最近更新 更多