0

I have been reading docs for almost a week now and searching to find an exact answer ! When I use inline setState() for a onClick event, It works perfectly fine but when I move the setState() to a function named updateCount() in my class, It does not work for the first time and I get the reason.

The problem is I added async/await to the function, strangely it works. ( I am aware of other methods )

The question is why it works with async/await?

(By the way when I use VS Code, I get this massage : 'await' has no effect on the type of this expression. but it actually has an effect so maybe that is a bug in react JS ?! )

Original code that works fine :

class LastTest extends Component {
    
    state = { count: 0 }
    componentDidMount() {
        document.title = `You clicked ${this.state.count} times`;
    }
    componentDidUpdate() {
        document.title = `You clicked ${this.state.count} times`;
    }
    render() {
        return ( 
            <div>
                <p>You clicked {this.state.count} times</p>
                <button onClick={() => this.setState({ count: this.state.count + 1 })}>
                Click me
                </button>
            </div>
        );
    }
}

Bad code that does not update count for first click:

class LastTest extends Component {
    
    state = { count: 0 }
    componentDidMount() {
        document.title = `You clicked ${this.state.count} times`;
    }
    updateCount(){
        this.setState({ count: this.state.count + 1 });
        document.title = `You clicked ${this.state.count} times`;
    }
    render() {
        return ( 
            <div>
                <p>You clicked {this.state.count} times</p>
                <button onClick={() => this.updateCount()}>
                Click me
                </button>
            </div>
        );
    }
}

Updated code and added async/await to the function updateCount() :

class LastTest extends Component {
    
    state = { count: 0 }
    componentDidMount() {
        document.title = `You clicked ${this.state.count} times`;
    }
    async updateCount(){
        await this.setState({ count: this.state.count + 1 });
        document.title = `You clicked ${this.state.count} times`;
    }
    render() {
        return ( 
            <div>
                <p>You clicked {this.state.count} times</p>
                <button onClick={() => this.updateCount()}>
                Click me
                </button>
            </div>
        );
    }
}
Nima
  • 118
  • 9
  • I suspect the observation that "it works with `await`" may be a false positive and something else is happening. `setState` is not a `Promise` to be awaited. It's "asynchronous" in the sense that the operation will complete at some later time. But it's not awaitable. – David Dec 14 '22 at 14:40
  • The question is why it works with async/await and I do not think this question is a duplicate. Please unclose this so experts can demonstrate. – Nima Dec 14 '22 at 14:42
  • 2
    You can remove the async/await and use a callback in your setstate, like this ``` updateCount(){ this.setState({ count: this.state.count + 1 }, () => { document.title = `You clicked ${this.state.count} times` }); }``` – unhackit Dec 14 '22 at 14:42
  • Isn't updating a react component's state considered to be an async task ? – DanteDX Dec 14 '22 at 15:01
  • Exactly but why it can't be awaited ? `setState` is not a promise as David mentioned right? – Nima Dec 14 '22 at 15:02
  • Most likely that, state updates are batched, awaiting flushes those changes and state changes are available after the await in the same function – Azzy Dec 14 '22 at 15:28

0 Answers0