[React] - useEffect vs useLayoutEffect in React

Truong Bui

Published on: Last updated:

react

In React, useEffect and useLayoutEffect are two hooks that allow us to perform side effects in our functional components. They are similar in many ways, but there are key differences that can affect when and how you use them.

useEffect

useEffect is a hook that allows you to perform side effects in your components. Side effects could be data fetching, subscriptions, or manually changing the DOM. useEffect runs after the render is painted to the screen.

import React, { useEffect, useState } from 'react'
import ReactDOM from 'react-dom/client'

function RandomNumber () {
	const [value, setValue] = useState(0)

	useEffect(() => {
		if (value === 0) {
			setValue(Math.random())
		}
	}, [value])

	return (
		<div>
			<h3>Random number: {value}</h3>
			<button onClick={() => setValue(0)}>Generate</button>
		</div>
	)
}

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
	<React.StrictMode>
		<RandomNumber />
	</React.StrictMode>
)
Library: react v18.2.0 - react-dom v18.2.0

As you can see, there is a flicker effect when we click on the Gererate button because useEffect will run after the render is painted to the screen.

The order of render with Gererate something like:

  • Click Generate button
  • Render
  • UI updated
  • useEffect run
  • Render
  • UI updated

Using react chrome plugin

useEffect

useLayoutEffect

useLayoutEffect , on the other hand, is identical to useEffect but it fires synchronously after all DOM mutations. This means it runs before the browser has a chance to paint the screen. This can be useful when you need to make DOM changes and want to prevent a flicker effect.

import React, { useLayoutEffect, useState } from 'react'
import ReactDOM from 'react-dom/client'

function RandomNumber () {
	const [value, setValue] = useState(0)

	useLayoutEffect(() => {
		if (value === 0) {
			setValue(Math.random())
		}
	}, [value])

	return (
		<div>
			<h3>Random number: {value}</h3>
			<button onClick={() => setValue(0)}>Generate</button>
		</div>
		)
}

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<React.StrictMode>
	<RandomNumber />
</React.StrictMode>
)
Library: react v18.2.0 - react-dom v18.2.0

There is no flicker effect when we click on the Gererate button because useLayoutEffect will run synchronously after all DOM mutations.

The order of render with useLayoutEffect something like:

  • Click Generate button
  • Render
  • useLayoutEffect run and wait
  • UI updated
useLayoutEffect

When to use which?

  • Use useEffect for most side effects, including data fetching and integrating with other libraries. It doesn’t block the browser from updating the screen, which is crucial for keeping your UI responsive.
  • Use useLayoutEffect if you need to make DOM changes and want to prevent a flicker effect. Be careful, though, as this can lead to performance issues if overused.

Hope you find this article useful. If you have any questions, please let me know in the comment section below. 👇