useEffect() runs a callback after component is rendered useLayoutEffect() runs callback after component is executed, DOM is calculated, but before it really shows on a screen It is useful to calculate something based on element dimensions and move element somewhere based on calculations before rendering on screen, to avoid screen flashes. Do not use it until it is really needed, because it is synchronous and blocks browser. Example Let's synchronously delay message with 2s with useLayoutEffect(func, [state]) & useEffect(func, [state]) and check the difference.
import syncWait from '/functions/syncWait'
import useIsInitRender from '/functions/useIsInitRender'
function Component() {
const [state, setState] = useState(false)
const firstRenderForLayoutEffect = useIsInitRender()
const firstRenderForUseEffect = useIsInitRender()
const ref = useRef(null)
const toggleState = () => setState(!state)
useLayoutEffect(() => {
if (firstRenderForLayoutEffect) return
syncWait(2000)
ref.current.innerHTML += '<div>useLayoutEffect() triggered</div>'
}, [state])
useEffect(() => {
if (firstRenderForUseEffect) return
syncWait(2000)
ref.current.innerHTML += '<div>useEffect() triggered</div>'
}, [state])
return (
<>
<div> State: <b>{state.toString()}</b> </div>
<button onClick={toggleState}>Toggle state</button>
<div ref={ref}></div>
</>
)
}
Hook flow We can see the hooks flow from Donavon West useLayoutEffect() callback is executed first, then state change renders on screen, then useEffect() callback is executed.