Hint
Use useLayoutEffect only when you need to read DOM measurements and update state/DOM before the user sees anything (avoid flicker). For everything else, use useEffect.
const log = [];
// useLayoutEffect fires synchronously after DOM mutations but before paint
function simulateLayoutEffect(fn) {
log.push('DOM mutation');
fn(); // synchronous — blocking
log.push('browser paints here');
}
// useEffect fires after paint
function simulateEffect(fn) {
log.push('browser paints here');
queueMicrotask(fn); // async — after paint
}
// Scenario 1: useLayoutEffect
log.push('render');
simulateLayoutEffect(() => log.push('layout effect'));
// Scenario 2: useEffect
log.push('---');
log.push('render2');
simulateEffect(() => log.push('effect'));
setTimeout(() => console.log(log.join(' | ')), 10);render | DOM mutation | layout effect | browser paints here | --- | render2 | browser paints here | effect
Explanation: useLayoutEffect: fires synchronously after DOM update, BEFORE browser paints. useEffect: fires after paint. Layout effect can update DOM without the user seeing a flicker.
Key Insight: Use useLayoutEffect only when you need to read DOM measurements and update state/DOM before the user sees anything (avoid flicker). For everything else, use useEffect.