Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript React Components (2018) Stateful Components and Lifecycle Methods Update the Stopwatch State with componentDidMount()

Might the asynchronous setState() method be run before the next segment of synchronous code in some instances ?

Hello Treehouse colleague,

handleStopwatch = () => {
    this.setState( prevstate => ({ isRunning: !prevstate.isRunning }) );
    if (!this.state.isRunning) {
        this.setState( { previousTime: Date.now() } );
    }
}

Line "if (!this.state.isRunning)" is written supposing that the previous line "this.setState( prevstate => ({ isRunning: !prevstate.isRunning }) );" is always run afterwards in the execution order.

Might there be instances when the asynchronous setSate method is executed before, so that the !isRunning condition fails and previousTime won't be updated at all ?

P.S. We could pass the condition code lines as a callback function to the setState method and remove the "!" from the condition, but that way some miliseconds might get lost each time the user clicks on the start button.

Many thanks,

1 Answer

You could wrap setState() in a function returning a Promise, and then use this function with the await keyword to cause your code to wait until the state has been applied. 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
}

}

In the foo function, the await keyword causes the code execution to pause until the promise returned by setStateSynchronous has been resolved, which only happens once the callback passed to setState is called, which only happens when the state has been applied. So execution only reaches the console.log call once the state update has been applied.