Current section: Client Router 27 exercises
solution

Pending UI

Loading solution

Transcript

00:00 Let's start with the ship details. When I navigate between these different ships, I should see some pending state right there. So we'll go to ship details right here. Actually, ship details should be rendered inside of our app. So if we come in here, we'll find ship details right here.

00:19 Right there. There we go. So we want to wrap this inside a client component so that we can show some pending UI around it. Basically, we just want this class or this div right here to have some style for opacity 0.6 if we're in a pending state. The problem is this app component is a server component.

00:37 And so it doesn't have access to the pending state because this was all rendered on the server and the pending state is all hanging out on the client. And so what we have to do is move this div and this class details into a different component, which we have already done. If we dive into here, there's our div with the details. And we, in fact, even have the style and all of that wired up.

00:57 And then we pass our children. So this is us composing our server, renders the client, which then accepts some more server UI. So it's all nice and composed. It's beautiful. So let's change out this div for our ship details pending transition component.

01:15 And we no longer need the class name anymore. So we can just do empty object or null works just fine. And now everything remains unchanged about our UI, except that we're now loading the code for this. So this is interactive.

01:35 It's capable of accessing the router. So we're gonna want a couple of utilities here. We also have a spin delay, which will make things a little bit nicer also. We'll bring that in here in a second. And let's grab our location and next location from use router.

01:53 Now we don't actually have the next location. Right now, our router only exposes the location, right? So we need to change this to next location and then we'll derive our current location from use deferred value. So I'm gonna change this to next location and set next location.

02:14 And here, this will be set next location. And then we'll get our location comes from use deferred value from React. We pass the next location. So during the transitional period, the location will lag behind the next location. So we're able to update the next location

02:33 and our current location is going to just be what it was before until the transition is done and then it catches up. And so on top of this, we're also gonna want a is pending and start transition close enough. Use transition. There we go.

02:51 So this is gonna get us our start transition and our is pending UI or Boolean. So we'll know, we'll be able to provide to people, hey, this is pending. And so rather than just being a global start transition that you get from React, we can use this specific one to our router context. Okay, great. So with both of those now,

03:10 we can come down here and add next location and is pending and that will be accessible now by our component. So not a lot of code changes here. We're just setting the next location. We're deriving it, our current location from the deferred version of the next location.

03:28 And now we can come back to our ship details pending. We have our location and our next location and we can determine whether these things, whether we're in a pending state based on whether the ship ID is different. So let's get our next ship ID

03:48 and our current ship ID. And if those things are different, then we know we're pending. So next ship ID is not equal to the current ship ID. And that should get us some pending UI. So let's save this. And if I click here, boom, we've got some pending UI. Awesome.

04:08 The problem is that, and sorry, accolades, hooray. Like let's not be, just move on from this. I think that's actually pretty cool that that's working now. But the problem is that we'll get a flash of pending state if the transition happens really quickly. And so we're gonna bring in use spin delay. This is a vendored version of spin delay.

04:27 You can feel free to dive into that, but the module is better, use the module. But we pass use or pass this to use spin delay. Now we can configure. We want to have the delay be 300 milliseconds and the min duration be 350. So if it shows up or if it shows up

04:46 within the first 300 milliseconds, then show the pending state. And if it shows up at all, then keep it there for 350 milliseconds, even if it's no longer pending after 300 or after like another 50 milliseconds, whatever, just to make sure we avoid a flash of pending state. And so now you will definitely sometimes see

05:05 some pending UI, but other times you might not. And you can feel free to go and adjust our database API to see how that impacts things. But we've gone through spin delay on previous workshops, so we're not diving any deeper into that. Great.

05:20 So we also have our other locations where we're actually gonna be pending inside of here, our search area. So if we go to our ship search results, this is a server component. And so we need to have a separate component

05:39 that manages wrapping the search results so that we can show that pending UI. And that's what this ship search is all about. If we look at our app right here, ship search is wrapping our results right here. And we're passing results as a prop. So our search results, which comes as a server component,

05:59 can be rendered by the ship search, which is a client component. So our results are right there. We render those right down in here inside of the suspense boundary. Okay, so with all that now, we need to get the next location. Next location. And we're gonna need our parse location state, so we'll bring that in also. Whoops, right there.

06:21 And now we're gonna say the search or previous or current search. Here we go, current search. And our next search. And then we're pending if those two are not the same. There we go. So now I do, oh, right,

06:41 and we need to make sure that our pending does update. And it looks like it does. So we're missing something because we definitely should be, oh, ha, I forgot to refresh the page. There we go. All right, awesome. Galaxy Cruiser. And then, of course, we wrap this in useSpinDelay,

07:01 which I'll just grab from up here. So we avoid the flash of pending state. And we can configure this. Also, we'll say a delay of 300 milliseconds and a minDuration. Whoops, minDuration of 350. That way we avoid a flash of pending state.

07:20 So I type INF, and you'll see sometimes you get the pending state, other times you do not. And it just ultimately comes down to will you get a flash of pending state? And there we go. We got pending UI. The most important aspect of all of this was in our index right here, where we switched our state

07:40 to be managing the next location, and then we get the current location using useDeferredValue so that the current location can kind of lag behind. During a transition, it'll lag behind the next location. Once the transition is done, then they're right back together again. Pretty sweet.