Hint
useEffect fires after the browser has painted — asynchronously after render. You can't read DOM layout in useEffect and expect the browser to have painted. Use useLayoutEffect for synchronous DOM reads.
const log = [];
// Simulates synchronous render then async effects
function renderComponent() {
log.push('render');
// useEffect scheduled after render (like a microtask/macrotask)
queueMicrotask(() => {
log.push('effect');
});
log.push('render complete');
}
renderComponent();
log.push('caller continues');
// Print after all microtasks
setTimeout(() => console.log(log.join(' → ')), 0);render → render complete → caller continues → effect
Explanation: Render runs synchronously (render, render complete). Caller continues synchronously. Then microtask fires (effect). setTimeout runs last.
Key Insight: useEffect fires after the browser has painted — asynchronously after render. You can't read DOM layout in useEffect and expect the browser to have painted. Use useLayoutEffect for synchronous DOM reads.