Avoid Flashes of Content in React with useLayoutEffect

Ryan Harris
InstructorRyan Harris

Share this video with your friends

Send Tweet
Published 2 years ago
Updated 2 years ago

At first glance, the useLayoutEffect and useEffect hooks look the same because they have a very similar function signature. There is, however, a subtle but important difference between them: the timing of when they get executed.

While useEffect runs after the DOM paints to avoid blocking the page load, useLayoutEffect runs before the DOM paints, which can help avoid issues with positioning or styling. Generally speaking, you want to use the useLayoutEffect instead of useEffect when you are interacting with the DOM directly.

Like useEffect, useLayoutEffect takes two arguments: a function and an optional dependency array.

useLayoutEffect(() => {
	// Runs every time the component renders
}, [])

useLayoutEffect(() => {
	// Runs only on initial render
}, []) // Optional second argument: dependency array

useLayoutEffect(() => {
	// Runs only when 'apiData' changes
}, [apiData])

Ryan Harris: [0:00] Let's add an effect hook here, useEffect. We'll say const greenModal = document.querySelector. The className is " .Modal--lime". We'll say greenModal.style.transform = "translateX(-50%)". Then, we'll say greenModal.style.left. It's going to be 50% because these are absolutely positioned. greenModal.style.top = "". Now, if we say this, you'll notice that our green modal has moved to the top of the screen.

[0:54] If we come over here and refresh, you can see that this modal is blinking a little bit, because it's actually being positioned after the DOM paints, so we're getting a little flash of unwanted content.

[1:05] To prevent that, we would use the useLayoutEffect hook because it runs before the DOM paints. If we add a useLayoutEffect hook here, and we say const purpleModal = document.querySelector, we'll do the same thing, it's going to be " .Modal--purple". We're going to say purpleModal.style.transform = "translateX (-50%)", purpleModal.style.left = "50%" as well, and purpleModal.style.bottom = "".

[1:55] If we refresh the page, you can see that the green modal is flashing because it's being repositioned after the DOM paints. The purple modal, on the other hand, is staying in the same place because the styles were applied before the DOM painted.

[2:09] In summary, useEffect and useLayoutEffect have the same function signatures in taking a function, as well as an optional dependency array. The difference is that they run at different times. useLayoutEffect runs before painting, whereas useEffect happens after the DOM paints.

Alex
Alex
~ 6 months ago

Heads up, I think your first useLayoutEffect hook in the above code block should omit the dependency array [] in order to be loaded on every render.