I sort of noticed that alot of people do not know the difference between the useEffect
and useLayoutEffect
hooks in React. Finding a use case for useLayoutEffect
seems like a very hard task.
Let's dive straight into it and see what this hooks are really all about, their difference(s) and when to use them.
useEffect
useEffect
allows you perform side effects from a function component. When useEffect is called, React knows to render your side effect only after changes are made to the DOM
React runs the effect after every render if you do not pass in an array of dependencies. useEffect
runs after the component is mounted and will run again if any of its dependencies changes
But if you need your side effect to fire synchronously after the DOM mutation, that is, before the next browser paint without the user ever noticing any flickering or visual inconsistency then you need to use useLayoutEffect
useLayoutEffect
useLayoutEffect
fires synchronously after the DOM mutation and before the browser get to paint the new changes. This hook is especially useful for performing DOM measurement like scroll height, scroll width, scroll position and other style on any DOM element.
Let's make some example codes
useEffect(()=>{
console.log("I will run second instead of first")
},[]);
useLayoutEffect(()=>{
console.log("I will run first")
},[])
Javascript script is a single-threaded programming language. Suffice to say, it runs from top to bottom. But here if you check the console, "I will run first", that is, the useLayoutEffect
actually runs before the useEffect
runs. This is because useLayoutEffect
is fired synchronously after DOM is mutated and before the browser paints the new changes.
Okay, I will like you to notice the change well in order to better understand how it works. Let's reference a DOM element with the useRef
React hook and let's perform some changes with the two side effect hooks we've been talking about
import React, {useRef, useEffect, useLayoutEffect) from 'react'
const App = () => {
const inputRef = useRef(null)
useEffect(()=>{
inputRef.current.value = "another user"
},[]);
useLayoutEffect(()=>{
console.log(inputRef.current.value)
},[]);
return(
<div>
<input type="text" value="EmmanuelTheCoder" ref=
{inputRef}/>
</div>
);
}
export default App;
Once the component is rendered, the input value becomes "another user" but the console says "EmmanuelTheCoder".
The useLayoutEffect already fired synchronously after the DOM mutation, before the browser could paint "another user"
I hope you got it.
Hey wait, one more thing!
React 18 brought some really good update to useEffect
hook.
Starting in React 18, the function passed to useEffect will fire synchronously before layout and paint when it’s the result of a discrete user input such as a click, or when it’s the result of an update wrapped in https://reactjs.org/docs/react-dom.html#flushsync. This behavior allows the result of the effect to be observed by the event system, or by the caller of https://reactjs.org/docs/react-dom.html#flushsync.
Top comments (11)
Thank you for the simple and to the point information!
I'm glad you find it helpful.
@emmanuelthecoder , I read your article, Actually yesterday I thought I would write article of
UseEffect
andUseLayoutEffect
but........,after reading your article I thought not necessary to write article on that topic because you can clear all points in Very Simple Manner.
Another thing is that
UseEffect
andUseLayoutEffect
is called after render method called means whenver any DOM mutation occured but if we don't pass array dependency so it's called in infinite loop. That thing applied on both UseEffect and UseLayoutEffect.So, It's necessary to pass Empty array dependency in the hook as second argument
Thanks for the kind words and the additional point. I'm glad you found the article helpful.
Would be glad if you could give me a follow here and share the article.
Yes, yes, but @doshiparth642 has a good point, your article is incorrect in the sense that it doesn't follow the recommended practices.
An
useEffect
oruseLayoutEffect
must always have a dependency array, since you don't want it to run every time.@doshiparth642 pointed that out and you replied with a copy-paste answer, instead of fixing your code.
This article could have been better written by OpenAI (or at least checked by it).
You don't need to change the code, but i leave this comment here for posterity pointing out your apparent inability to correct things :) or to answer to comments
Hi @svbzctvxapkkyc
Thank you for pointing out the apparent oversight. I have updated the article.
"...Pointing out your apparent inability to correct things..." — if that was the case for me, I could simply hide your comment. But that's not it as I am happy to take corrections and effect them — no one is an island of knowledge.
Also, at the time of writing this article, ChatGPT wasn't released yet but I guess you wouldn't know this.
You're right, 2022 not 2023 :) Sorry for that oversight.
Thank you for the correction! :)
Thanks, the explanation is clear, but about this sentence:
it depends on the dependency array of the useEffect.
Yes! by default, React runs side-effect on every render but this can be customized by passing in an array of dependencies.
Seems it's your first week with React, Emmanuel. How's the progress going? :)
Ok, I know I had a case on my previous project where it was better to use useLayoutEffect over useEffect. Thanks.