Intermediate React, v5

useLayoutEffect & useID

Brian Holt

Brian Holt

SQLite Cloud
Intermediate React, v5

Check out a free preview of the full Intermediate React, v5 course

The "useLayoutEffect & useID" Lesson is part of the full, Intermediate React, v5 course featured in this preview video. Here's what you'd learn in this lesson:

Brian explains that useLayoutEffect is called immediately after the render function so any calls to setState inside that effect will result in only one re-render instead of two.


Transcript from the "useLayoutEffect & useID" Lesson

>> So I have this bit of UI and I want to be able to measure this text area whenever a user lets go of the mouse, right? Why can't I just do useEffect to measure that? Well, let's try it. Let's get useEffect in here. So, for how the code works, just looking at this, You have a width and a height set as hooks, right?

And then if you remember from previous, an effect happens immediately after a render ends. However, an effect is actually not synchronously afterwards, right? So you have the render function that happens. There's some pause, the pause will be milliseconds, right? It's basically the next tick, the next frame, whatever you wanna call it, and then it'll run your function.

Why is this problematic for something like this? So, if I come in here and do this, save it. Might be kind of hard to see over the stream, but if you do, you'll get kind of like a ghostly effect there. You can see it kind of like bounce a little bit, right?

That's because it's happening twice, right? In fact, you can see it there, even if I'm just clicking on it. So what layout effect is going to do is it's going to allow you not have to wait that like little pause. It's actually going to happen immediately after the end.

So actually synchronously after your render function ends, your layout effect is going to run. And so that if you call setState, inside of that effect you'll get one rerender instead of two rerenders. So if I do useLayoutEffect here now, notice I don't get that ghosting effect anymore, that's because I'm calling this inherence.

So I'm actually only getting one rerender of two rerenders. You might ask yourself, how is this useful, the answer is almost never. [LAUGH] It's really only useful for exactly what I'm trying to hear, which is you have something, and you need to measure something that happens the DOM, but it can only be measured after it's been rendered.

That is when layoutEffect is very useful. Everything else just useEffect. The other kind of minor caveat, if you're migrating something from a class component to an effect and it depends on that immediate behavior. Class components, the component did mount used to work like this, actually still works like this, right?

And so sometimes that behavior is dependent on this immediate synchronous effect happening. So useLayoutEffect can be useful for migrating from class components to function components where you have that relied upon order happening. Otherwise, always useEffects. I'll be honest with you, I don't think I've ever professionally used a layout effect.

I could see where it'd be useful, right? For something like this, where I'm actually measuring something happening. I'm sure you can imagine some animation where you need to measure how far something's gonna go inside of a DOM element, and you need to measure it. Layout effect is exactly there for that purpose, everything else just useEffect.

>> So if use memo returns a function and behaves like useCallBack?
>> Correct, that is exactly true. So that was layout effect. Let's take a look at useId. This one is occasionally useful, and it's very useful, particularly in the case I'm about to describe to you. Let's say you are making a design system for your company, right?

For example, Stripe has a design system that we work on. And you have some sort of fancy input, right? That has a label, it has an input, it has other stuff that associates all the stuff together. A good example, this is associating together a input and a label, right?

So if you click on the Label, it highlights the input. Most of us are familiar with how that works, right? If you look at that here, I have a input, I have a label, and I have to match the HTML 4 to the ID of the input. What if I have four different inputs, I can't just say, ID is equal to 1, right, because that would make all of these have the exact same ID, that doesn't work, right?

So I need some sort of unique identifier that works in pairs, or not pairs, but that's internally consistent to a component, but I can use it multiple times, right? Cuz if you look down here, I'm using this LabelInputPair four times. Not only that, I need it to work also on server-side rendering, right?

So I need it to be consistent across renders and destinations and all that kind of stuff. That's why useId is useful. If I do useID, it will give me back a unique identifier that will be consistent within this label input pair, and then I can use multiple times across various different renders.

Does that make sense, the use case why I need this? I need an Id, that per instantiation of a component is consistent. So for example, I do useId, you can see my rendering it out here. This one's r0, r1, r2 r3, so on and so forth. And that's how I'm able to associate that this input, this one here goes this input here, this label here goes with this one here.

Otherwise, I'd have to have my useIdComponent up here. Have some sort of counter or something like that that would feed into it, it'd be get annoying really quickly. So, that's what useId is for. I have used this one before professionally, exactly this, it's useful for things like design systems.

And specifically for label and inputPairs it's very, very useful. You'll notice its partly hard to see here, but there's colons here, they intentionally do that, so you cannot do CSS selectors on those Ids. Cuz I knew people would do it and then they're, we don't want you to do that, because we're never going to guarantee you that it's r0 on this computer, and it's gonna be r0 on that computer as well, right?

They didn't want that, they want you to use some other way of selecting things for CSS, but that's why there's colons there so that you don't use it for CSS selectors. One more thing I was gonna add here. What happens if I need to useId multiple times, but it needs to be inside of one component?

They suggest don't do const Id2=useId again. What they suggest is that const Id2 equals your id plus some modifier right and then use that. I'm just pulling that directly from the React docs. They suggest don't use useId multiple times inside of one component, cuz it's not necessary. Yeah, and this is safe across server-side renders and client-side.

Yeah, Mark.
>> Could it be used for keys when mapping through an array if we don't have any unique value?
>> So here's the place where I envision it could be used as a key. Let's say I had a select, okay, I have a select inside of here instead of an input and every one of my select has a different, Array of key or a array of options, right?

I could use that as the key prefix to whatever set of options that I have. You will never just like use an id directly inside of a for loop, right? Because you remember we don't use hooks inside of for loops, right? So I think generally the person's asking if I'm intuiting what they're trying to get at, I think the answer is no, don't useId that way.

But I did wanna carve out that I think there are occasions where you're trying to differentiate this set of options from this set of options as holistically different lists. Probably makes some sense to use it in that particular case.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now