
Lesson Description
The "State Management with URL Parameters" 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 highlights the benefits of using URL query parameters for form state, such as preserving data on refresh, enabling sharing, and supporting the back button. He introduces the Nuqs library to simplify syncing state with the URL and emphasizes the value of explicit state management to avoid inconsistent transitions.
Transcript from the "State Management with URL Parameters" Lesson
[00:00:00]
>> David Khourshid: So what I wanna talk about now is using URL, the query parameters for state management. This is something that is typically overlooked because it's just not something we think about. And also it's sort of difficult to do, especially if you're using a framework like Remix or Next, they don't make it the easiest thing to synchronize state with the URL.
[00:00:28]
However, in many web applications, and this goes back even to the early 2000s, 1990s, the URL was actually the source of truth. So think about it. Let's say that you want to have some sort of form or some sort of view where you're searching for things and you want to actually have it so that the URL maintains the state, so you have everything in query parameters.
[00:00:57]
There's a lot of benefits to this. First of all, the form data is not gonna be lost on page refresh because you already have that data in the query parameters and you could use it directly on the page. Also, that long string with the query parameters, you can bookmark it, you could share those URLs.
[00:01:17]
And the back button is actually going to work and preserve that form state because we're using the natural history mechanism of the browser to maintain that state for us. So again, URLs are really, really overlooked when it comes to state management. But honestly, a lot of our applications can really benefit from using the URL as a source of truth for state.
[00:01:42]
There is an external library called nuqs and N-U-Q-S that does make this pretty easy to do. And I'm going to demonstrate to you how nuqs can make this a lot easier. But first let's take a look at the actual problems that we're dealing with. So if you go to exercise-URL, we have our flight booking form as normal.
[00:02:08]
We have our one way flight, we could put in a destination, our departure date, the number of passengers, and search for flights. You know what, I don't actually wanna go to Tokyo, so let me go back and change that to Osaka. Wow, okay, so everything changed except the number of passengers for some reason.
[00:02:33]
But everything changed and everything disappeared. And now as a user I'm a little bit frustrated about that. So that's just not cool. So if I put a destination here, go to search flights and let's say that, okay, I actually like these results for this imaginary place that I searched and I want to sort by duration, see the direct flights, and actually share this with one of my friends.
[00:03:05]
I can't because there's no query parameters, there's nothing for me to share that basically when I reload, first of all, this view is going to go away. And even if that view didn't go away, like if it was a different page, I would lose all of my results.
[00:03:21]
So it's just really not a good situation. All right, so how can we actually fix that? So if you go to urlpage.ts, we are going to use a library called nuqs, N-U-Q-S. So we have a bunch of use states here. And we've done so many exercises where it's like, okay, yeah, let's consolidate these, let's put them in a reducer, et cetera.
[00:03:48]
We're not actually going to be doing that here. Instead we're going to be replacing this useState with use query state from nuqs. The only difference here is we want to give it a name. So it's going to be, for example, usequery state destination and then this is going to be usequery state departure arrival.
[00:04:16]
This is what shows up in the URL. And then this is one way set is one way. This one is a little bit different. All of these are strings, or we could use them as strings. But with usequery state, it assumes that since the URL is a string, everything's gonna be a string.
[00:04:37]
It's not the case over here. We actually want to parse this as a Boolean value. And so the way that Nuqs works is we have a way to parse the value and so you could return the value as true and, and then you could go the other way around.
[00:04:52]
And so, based on the value that is set, we would set that to true or false. Or we could do things like set this as one or zero, it just needs to be a string. But Nuqs does have a lot of shortcuts for that. So we could just parse as Boolean and then give it a default of false, for example.
[00:05:19]
So now let's see this in practice, when we go back here, we are now going to see an error value prop on input. Interesting, don't care. So you are going to now see that when I toggle, for example, one way flight, it's updating the URL for us. And also because the default is false, that actually disappears when we set that to false.
[00:05:47]
So now we could enter a destination and you could see that it is changing in the URL as we are changing that. And also it's not pushing to history, instead it's replacing the history. So you're not going to get that annoying thing where when you go back it's toki and then you go back it's toke, etc.
[00:06:10]
Instead it's going to treat it as a single transaction. Then we could set the date. So we set the departure number of passengers. I think we forgot to add that in, it's okay. The idea is that when we search flights and we go back to our search, none of our data is lost, which is really awesome.
[00:06:33]
So if we take a look at the search results, then we could basically do the same thing over here. So this, we might need to change it because this needs to be an id. And so this goes back to an earlier lesson. Instead of duplicating states, we want to really instead derive it.
[00:06:56]
So we would want to set the flight id. And so this one, we use query state parses Boolean with defaults false. And there's another one here where we could parse as enum or. Sorry, it's not parse as enum, it's something else. It is, parse as string enum. Be careful of AI coding assistants because they will hallucinate different answers.
[00:07:25]
But yeah, so you can have things that go beyond a string and you could also have these string enums. We're deriving state over here, which is good, but yeah, so now we should see that this works when. And you could see that it's actually changing over here. When we actually change ascending, descending, etc, it is going to change in the URL.
[00:07:54]
So there's one more thing to do which is, let's see, forget what it is. Yeah. So if we go to the solution, because the other problem here is that if we reload it is going to go back to the original screen and we don't necessarily want that. So the way that we solve this in the solution is that we actually have a view variable.
[00:08:29]
And so just to show you what that looks like, we have view, set, view and then we're using query state of the current view that we're on. So having this in the reducer makes this a little bit easier. But yeah, so yeah, so that's a basic intro to using the URL query parameters estate.
[00:08:57]
It's something that I really encourage. Like when you have something where you want the URL to be shareable, you want the URL to be the source of truth. For part, if not all of your components in a certain view, definitely consider using the URL query parameters for states.
[00:09:16]
>> Speaker 2: What if instead of using a view parameter, we just check to see if history has anything pushed to it. So just if they essentially go to the URL and there's no history, there's nothing to go back to, then you could assume that they're going straight into the view of results.
[00:09:40]
>> David Khourshid: Potentially, yeah. And that could work in some cases. I just like to be explicit. And this view equals or step equals. This is something that you will see commonly in URL query parameters anyway where it explicitly says which step you're on. So it's a difference between implicit versus explicit states.
[00:10:07]
>> Speaker 3: And just to double check here, the first couple params, that's actually from the first page.
>> David Khourshid: Yes, and that's so that we have that. And look, if I go back, oops. Or forward, I did that wrong. We could go back. We could go forward and get those search results back.
[00:10:29]
And forward works pretty naturally, which is pretty nice. But yeah, going back to the original question of what if the user changes that? Like let's say that they're, I don't know, playing a game or they want to jump directly to confirmation. This is why you would want either something on the server or you could have frontend logic that says, are we in an impossible state?
[00:10:55]
Just use Zod to validate that and basically kick them out if they're not supposed to be on that part of the URL or if the state is just inconsistent with what is expected in the application.
>> Speaker 2: I think that's why partly on the reducer you always have the default just basically return whatever it was back at them so that there's no actions taken that they would want to be able to get into.
[00:11:26]
>> David Khourshid: Right, right, exactly. And that's another good point about reducers is that potentially you could limit when actions actually should change the state. And that's something that I haven't dived too deep into. But right now, when we're using useReducer a lot, it's action first. But if you do it state first, then that's another way that you could prevent impossible states.
[00:11:49]
So for example, if I'm loading data, but I have a back button and I go back to the form where I just enter my input and everything like that. And I have an action that's like, all right, I got the search results, take me to the results page.
[00:12:08]
What should actually happen is I should only be able to go there if I'm in a state where I'm waiting for results. If I'm not in that state, like if I'm on the first step, where I'm just entering search information, then that action should be completely ignored. So that's a core principle of state machines just preventing impossible transitions like that.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops