
Lesson Description
The "State Anti-Pattern Exercise" Lesson is part of the full, State Management at Scale in React & Next.js course featured in this preview video. Here's what you'd learn in this lesson:
David instructs students to complete an exercise on recognizing and fixing anti-patterns like redundant states, improper use of refs, and duplicating states. David also suggests referencing static values like user profiles outside of useState to keep functions self-contained and easily testable.
Transcript from the "State Anti-Pattern Exercise" Lesson
[00:00:00]
>> David Khourshid: And so what we're going to be doing is we're going to jump into the exercise. So what I want you to do is go to anti patterns and go to page TSX and there's going to be a lot of different exercises and hopefully this should be pretty quick for you to do.
[00:00:22]
The point is to build the muscle memory to actually, to actually avoid these any patterns and simplify these components based on what we've learned, which is the proper use of refs deriving states instead of duplicating it and also avoiding redundant states. So let's go ahead and take a few minutes and jump into this and let's get started.
[00:00:57]
All right, so let's go through all of these anti patterns that again, I'm sure that you've seen in your code bases. And again, these exercises are meant to get the muscle memory in your hands of recognizing these anti patterns and fixing them so that you could do it in your own code base.
[00:01:14]
And I recommend for this exercise and all of the other exercises, try to do it in the code bases that you have access to or at least try to identify or search for them. Honestly, if you search for use date in your code base, you're going to see a lot of these.
[00:01:31]
But okay, so let's take a look at this first one. Filter destinations. Again, we see this combination useState and useEffect hook where we're setting the filter destinations. What we could do instead is I am going to do const oops filtered destinations and I'm just going to directly compute that in render.
[00:01:58]
Now I can get rid of this use date and I got rid of the other useEffect and it still works with each of these you could go and just make sure that everything still works. All right, and so for the other exercises, it's all very similar too. Again, instead of setting directly just const total cost and then get rid of that useEffect and get rid of that state.
[00:02:30]
The more code you delete, the better. This is a very satisfying one to do just because the pattern will hopefully stand out to you like a sore thumb and then you can just immediately do it. This one is a tiny bit more complicated, but only because there's more code over here.
[00:02:50]
Still not a problem. We could do const available dates and get rid of this use dates, get rid of the use effect because we're already going to have the updated booked dates inside. Okay, so now let's go take a look at some other patterns. So for example, let's see, I wanted to see a ref- 1.
[00:03:23]
Okay, here's a good one. So this is the same timer example that we were talking about, you know, with a booking timer. Instead of this, let's use a Ref. So const timerIdRef = useRef. And then we now have access to that timerIdRef via timeridRef.current. And then so instead of setting it directly over here, we can just say timerIdRef.current equals that Id.
[00:03:58]
And then we could do the same thing over here. Since we're clearing the timer, we could say timer ID ref current is null and then we could just clean up the rest. So we could say this should be timer ID ref current. Let's give this a proper type of NodeJS.Timeout or null.
[00:04:24]
And then let's also set timerIdRef.currents. We'll set that to null and we'll also change these too for the sake of time. I'm just using cursor, but it's essentially the same thing. We are replacing timer ID with the timer ID ref.current and so our effect is now no longer going to change change multiple times.
[00:04:52]
So, same thing with the scroll position tracker. We could, instead of keeping track of the last scroll position in use dates, we could use a ref. So const last, oops, LastScrollPositionRef = useRef and we'll give it a number type. And this is just going to be zero. So now we can get rid of this useState and we could update the Ref instead.
[00:05:21]
So LastScrollPositionRef.current = currentPosition over here. And then so set last scroll position and then we could just update the rest. So we are going to get that. And now we no longer need this use or actually no, we still need that use effect, but we no longer need anything in there, just because the effect does not need to rerun whenever the scroll position changes or sorry, whenever the last scroll position changes.
[00:06:03]
So I want to skip ahead to the hotel selection one that we talked about. So again, this is a case where we have redundant states. We are selecting a hotel instead of selecting the, you know, the hotel id, which makes things a lot simpler. So instead of this, we could just select the hotel ID and then set this to set selected hotel id.
[00:06:31]
So instead of trying to grab the type of the hotel, this is just going to be a string. And so instead of this, we are going to be handling the hotel ID instead, which is going to be a string. And so we could set the hotel ID to that hotel id and now the selected hotel is going to be derived from the selected hotel id.
[00:06:56]
So Const selected hotel equals we have our hotels already, so hotels and we're going to find the hotel where the hotel ID is equal to the selected hotel id. And so now we have derived states and we're preventing just having redundant states. And so a similar thing is going to be done with things like, you know, these other exercises over here, this is a pretty common one where we have our user profile from somewhere, but we're also trying to manage the state of each of these components.
[00:07:37]
And so, you know, we're trying to set the username and all of the other fields over there.
>> Speaker 2: We just wanna use userProfile.name.
>> David Khourshid: Yeah, yeah, yeah,
>> Speaker 2: yeah. As the we don't even need to use use state, we could just reference the state from up above.
>> David Khourshid: Yeah, exactly, that's exactly right.
[00:07:58]
So instead of doing all this, yeah, you could basically just use user profile name. You don't need to pull it in from me to these useSates. So then here we have user profile name, email preferences, budget and preferences traveltype. A bit of a contrived example, but yeah, that just goes to show you that if you can avoid redundant states, then you don't really need to have all of those multiple use dates handling that.
[00:08:36]
So that's a solution to a few of these exercises and the other ones just follow suits in the same way. Any questions about any of these warm up exercises that we did? Yes,
>> Speaker 3: one thing I try to do is especially when it comes to static values, for instance the user profile, rather than place the whole object inside of use state, especially if that entity isn't going to be change or modified, since we don't have a set callback or function passed in here as well, that to just leave it outside of the scope of the function.
[00:09:20]
So instantiate it above the function and then just reference it inside kind of a closure, right? Where we're referencing it outside of the function, I would imagine. Would you recommend that over the practice that's currently happening there?
>> David Khourshid: Yes, I would. And again, this is a contrived example.
[00:09:40]
So ideally this user profile would come from props or if it does come from somewhere else, you can bring it in as a closure. Although I would say just be wary of closures just because you want your function to be self contained and easily testable. So if you were trying to extract this component out and test it, then that closure data might not be available for whatever reason.
[00:10:06]
So it might be something where you would pass it in via context or pass it in via props but yes, the idea is that in this case the user profile isn't changing, so it does not need to be inside of a use dates, which is another important thing.
[00:10:21]
I've seen use dates where there is no setter at all, so it sort of makes them a little bit useless. I think the most important takeaway here is that you should try to derive state as much as possible. So we're going to be seeing that in other exercises as well, where that principle really comes into play.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops