useEffect vs useLayoutEffect
by Rakib, Frontend Developer
useEffect vs useLayoutEffect in React
React provides two essential hooks, useEffect and useLayoutEffect, for handling side effects in functional components. While both serve similar purposes, they differ in their execution timing and use cases. Let’s dive into their distinctions and explore when to use each with examples.
What is useEffect?
useEffect is a React hook used for performing side effects like data fetching, setting up subscriptions, or updating the DOM.
When does it run?
- Runs after the browser has painted the screen.
- Non-blocking, allowing React to update the UI first before executing the effect.
Use Cases
- Fetching data from an API.
- Setting up event listeners.
- Updating state based on props.
Example
import React, { useEffect, useState } from "react";
const ExampleWithUseEffect = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Effect executed after paint");
document.title = `Count: ${count}`;
}, [count]); // Runs whenever `count` changes.
return <button onClick={() => setCount(count + 1)}>Increment Count</button>;
};
export default ExampleWithUseEffect;What is useLayoutEffect?
useLayoutEffect is similar to useEffect but fires synchronously after all DOM mutations and before the browser paints the screen. This means useLayoutEffect blocks the rendering process
When does it run?
- Runs before the browser paints the screen.
- Blocking, ensuring that the DOM updates are applied immediately.
Use Cases
- Reading layout or style values (e.g., element dimensions).
- Synchronously re-rendering based on layout changes.
- Fixing layout glitches during reflow.
Example
import React, { useLayoutEffect, useRef, useState } from "react";
const ExampleWithUseLayoutEffect = () => {
const [width, setWidth] = useState(0);
const divRef = useRef(null);
useLayoutEffect(() => {
const rect = divRef.current.getBoundingClientRect();
setWidth(rect.width);
console.log("Effect executed before paint");
}, []);
return (
<div ref={divRef} style={{ width: "100%", background: "lightblue" }}>
<p>Width: {width}px</p>
</div>
);
};
export default ExampleWithUseLayoutEffect;Summary
- useLayoutEffect: If you need to mutate the DOM and/or do need to perform measurements
- useEffect: If you don't need to interact with the DOM at all or your DOM changes are unobservable (seriously, most of the time you should use this).
One special case
One other situation you might want to use useLayoutEffect instead of useEffect is if you're updating a value (like a ref) and you want to make sure it's up-to-date before any other code runs. For example:
const ref = React.useRef();
React.useEffect(() => {
ref.current = "some value";
});
// then, later in another hook or something
React.useLayoutEffect(() => {
console.log(ref.current); // <-- this logs an old value because this runs first!
});So in situations like that, the solution is useLayoutEffect.
Conclusion
It's all about defaults. The default behavior is to let the browser re-paint based on DOM updates before React runs your code. This means your code won't block the browser and the user sees updates to the DOM sooner. So stick with useEffect most of the time.