Hint
In useEffect with async code, the synchronous part runs immediately after render. Promise resolutions run as microtasks. State updates from async code still trigger re-renders.
const log = [];
// Simulates an async useEffect
function simulateEffect() {
log.push('effect start');
Promise.resolve('data')
.then(data => {
log.push('data received: ' + data);
return data.toUpperCase();
})
.then(upper => {
log.push('set state: ' + upper);
});
log.push('effect end (sync part)');
}
simulateEffect();
log.push('after effect setup');
setTimeout(() => console.log(log.join(' | ')), 10);effect start | effect end (sync part) | after effect setup | data received: data | set state: DATA
Explanation: The synchronous parts run first (effect start, effect end, after effect). Promise .then callbacks run as microtasks — after sync but before setTimeout.
Key Insight: In useEffect with async code, the synchronous part runs immediately after render. Promise resolutions run as microtasks. State updates from async code still trigger re-renders.