React executes the useEffect
hook asynchronously after the real dom is rendered. On the other hand, the execution of the useLayoutEffect
hook happens synchronously before the real dom is rendered.
In other words, the useEffect
hook does not block browser painting, while the useLayoutEffect
does.
useEffect hook life cycle
- Component mounts or re-renders
- Virtual DOM mutations take place
- Real DOM syncs with the virtual DOM (paints the contents on the screen)
- Executes useEffect hooks
The useEffect
hook execution happens after the real dom is painted. Any method calls inside the useEffect
are asynchronous as well. Therefore, the useEffect
hook does not block the rendering process.
useLayoutEffect hook life cycle
- Component mounts or re-renders
- Virtual DOM mutations take place
- Executes useLayoutEffect hooks
- Real DOM syncs with the virtual DOM (paints the contents on the screen)
The useLayoutEffect
hook execution happens before the real dom is painted. Therefore, it blocks the actual DOM rendering process. Any method calls inside the useLayoutEffect
are synchronous as well.
Here is a simple example to illustrate the execution order of each hook.
import { useEffect, useLayoutEffect, useState } from "react"
export const App = () => {
const [message, setMessage] = useState<number>()
const time = Date.now()
useEffect(() => {
console.log("useEffect ->" + (Date.now() - time))
})
useLayoutEffect(() => {
console.log("useLayoutEffect -> " + (Date.now() - time))
})
return(
<>
<div>Message: {message}</div>
<div><button onClick={() => setMessage(Math.random())}>Change</button></div>
</>
)
}
export default App
When to use the useLayoutEffect hook?
The useLayoutEffect
hook blocks the UI. It is synchronous, and any method calls inside the useLayoutEffect
hook are also synchronous.
It is useful when I have to manipulate the DOM directly. Such as adding or removing DOM elements. The reason to perform the DOM manipulations inside the useLayoutEffect
is to make the changes invisible to the user because we see the real DOM after the useLayoutEffect
is done. Of course, we can use the useEffect
hook for this case, but the DOM manipulations may become visible.