Here’s what’s happening.
Synchronous
- you press X
- input.value is ‘HelXlo’
- you call
setState({value: 'HelXlo'})
- the virtual dom says the input value should be ‘HelXlo’
- input.value is ‘HelXlo’
- no action taken
Asynchronous
- you press X
- input.value is ‘HelXlo’
- you do nothing
- the virtual DOM says the input value should be ‘Hello’
- react makes input.value ‘Hello’.
Later on…
- you
setState({value: 'HelXlo'})
- the virtual DOM says the input value should be ‘HelXlo’
- react makes input.value ‘HelXlo’
- the browser jumps the cursor to the end (it’s a side effect of setting .value)
Magic?
Yes, there’s a bit of magic here. React calls render synchronously after your event handler. This is necessary to avoid flickers.