3

I've written a test case in Codepen

Run the test by clicking the button, then see the result from Browser Console.

You can see from the console log that even I called setState multiple times before await, it will only update the component once.

But if I call setState multiple times after await, it will update the component multiple times too.

Any idea why is this happening?

Code:

/*
 * 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'));
4
  • setTimeout does not return a promise that could be awaited. Commented Sep 24, 2018 at 8:25
  • 2
    stackoverflow.com/a/48731782/2630817 this can be helpful Commented Sep 24, 2018 at 8:36
  • Also, setState is itself asynchronous and React will flatten the first three calls if it can. Commented Sep 24, 2018 at 8:40
  • @remix23 I know setState is an asynchronous call but why after await it will be triggered every time whenever setState is called? Commented Sep 24, 2018 at 8:51

2 Answers 2

3

This happens because as this answer states React tries to batch setState calls and process them together when it can. But this is not the case with asynchronous computations because React (and anybody in general) can't predict and reproduce the order of setState's called asynchronously.

So in your case it fallbacks to just updating state 3 times.

Sign up to request clarification or add additional context in comments.

Comments

1

You can got this answer from React.Component life cycle doc (https://reactjs.org/docs/react-component.html)

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

Use this method shouldComponentUpdate(). This method allows your Component to exit the Update life cycle if there is no reason to apply a new render. Out of the box, the shouldComponentUpdate() is a no-op that returns true. This means every time we start an Update in a Component, we will re-render.

I add more code

  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 });
  }

Check my Codepen

So if you want to prevent unnecessary render custom method shouldComponentUpdate

1 Comment

I wasn't trying to prevent unnecessary render. I just want to know why after await it will trigger componentDidUpdate() whenever setState is called

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.