Avoiding the dreaded React Flicker

The basics of useEffect 🤖

If you've ever built an application with React, it's likely that you're familiar with useEffect. It's an extremely popular, and useful hook that is often called on to do things like fetch your data or update a vital piece of state. Let's consider a pretty basic useEffect scenario, and what exactly it means for your application.

  • You cause a render for your component
  • React will then render or call your component
  • React will then "paint" the screen, visually displaying the updated DOM
  • Its at this point your useEffect runs, fetching your data or calling a setState, or whatever your awesome application does

It is important to note that useEffect is asynchronous, and that most of the time useEffect is probably the hook you want to use.

The basics of useLayoutEffect 🎨

If you haven't used useLayoutEffect before, that's ok! You probably haven't needed to. We'll go over a use case further down, but it is a good idea to at least know its out there. So how does useLayoutEffect work? Again, very basically.

  • You cause a render for your component
  • React will then render or call your component
  • KEY DIFFERENCE It is at this point that useLayoutEffect will run
  • Only after all the various cool things in your useLayoutEffect hook are done running will React paint your render and visually update the screen

An important distinction here is that useLayoutEffect is SYNCHRONOUS vs the asynchronous useEffect hook.

First things First - what's the code look like? 💻

The good news is, the code to implement useLayoutEffect should look EXTREMELY similar if you've ever had occasion to call useEffect.

A code example from carbon showing how to call both useEffect and useLayoutEffect

Nothing too bad right? useLayoutEffect gets called just like useEffect with a dependency array and everything!

So when to consider Layout Effect? 🤷🏻‍♂️

More good news! It'll be SUPER obvious! Have you ever been working on your component and noticed a jerky, janky, flicker? If you haven't, try Googling React Flicker sometime, and you'll see exactly what I mean. For me, this occurred when I was creating my Resume Game for my portfolio. It's a choose-your-own adventure style game that uses clickable text nodes to advance the story and, in turn, important resume information. The problem I encountered is that I have a whole batch of stuff that needs to occur, and almost all of it has a direct impact on the visual aspects of the rendered component. I was seeing a horrendous flicker that was both jarring and very page-shifty (technical term). My text nodes would change, shift, morph in size based on text content, and then finally settle. It was like that scene from The Ring where the creepy girl is 2 meters away and then she flickers directly in front of you and kills you with her wet hair or whatever. In other words, not great. Here's an example of my text node code.

A code example of how a complex useEffect might be better implemented with useLayoutEffect

All this code happens synchronously BEFORE the page is visually presented to my users. This way, my text nodes and states have time to change over before they are painted - thus avoiding the dreaded React Flicker

Most of the time, useEffect will be exactly what you need. But if you have a large batch of processes that need to occur on render and you are seeing a disjointed flicker that makes your squishy little developer heart hurt. Give useLayoutEffect a try!