Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

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.