Advanced Remix

Pending UI Loading Spinner Solution

Kent C. Dodds

Kent C. Dodds

Professional Trainer
Advanced Remix

Check out a free preview of the full Advanced Remix course

The "Pending UI Loading Spinner Solution" Lesson is part of the full, Advanced Remix course featured in this preview video. Here's what you'd learn in this lesson:

Kent walks through the solution to the Pending UI Loading Spinner exercise.

Preview
Close

Transcript from the "Pending UI Loading Spinner Solution" Lesson

[00:00:00]
>> Welcome back to exercise seven. Hopefully you had a good time working through this. And we are going to just add a spinner. So, in the app layout route, this is the route responsible for rendering of this. It's basically the route for the logged in portion of the app.

[00:00:22]
So, if we look at the actual route, this route is responsible for the HTML, the head, the body, everything that's like common whether you're logged in or logged out. And then our Dunder app. That's what you call double underscore, I am told, our Dunder app components here, the app route is responsible for all the logged in user stuff.

[00:00:44]
That's why our login screen looks completely different from the rest of who logged in the app where we can have the fake books on the left and all that. So that's why we're here because we're gonna be adding a spinner to the fake books logo right next to that.

[00:00:57]
And we have a spinner implemented for you in this component right there. And so, if we come up and render that spinner, and we say visible, true. And we'll come over here and right, we're on a slow page, we'll deal with that. But there is our spinner, nice and spinny but we need to determine when should this spinner show up and when should it not.

[00:01:24]
So we're going to hook into with a hook, remix state for the transitions as they happen. So we're gonna get our transition is use transition and again this is coming from the remix, run, react, not from react. We shipped first, we're gonna change it because React is bigger than we are.

[00:01:48]
And also our name makes more sense to call it a navigation, so that's probably we will probably change it and it will probably be changed to transition. So now we need to determine what or we're gonna use the transition to determine whether we should be showing the spinner.

[00:02:04]
So we can determine if we are in a loading state. So we're transitioning, so we'll say, show a spinner is based on transition.state is not equal to idle. So if it's anything else and we are transitioning, there's a transition going on. We're submitting a form that is a transition or at least a form that is a transition in fetchers or not that doesn't apply.

[00:02:29]
But for forms that like redirect like or create new custom form for example, or we're navigating over to the customers, navigating between customers all of that will have a transition state of either, of one of the other two options here which TypeScript will Tossers loading or submitting. So, when we're submitting the form, and then loading is when we view revalidating or just transitioning between pages, we just get a loading state there.

[00:02:54]
So if we're anything but idle, then we know we're in a transitioning state. And so we should show the spinner, and that will do it for us. So if I go between customers, then we're gonna get our spinner right there and and go to another customer boom there is our spinner looks nice.

[00:03:12]
If I go between invoices now, that transition happens so quickly that we do not see the spinner and the reason for that, if we come down to our spinner is, we have it animating from zero to 100. We transition that over some time, so it's not transitioning fast enough for us to be able to see it.

[00:03:36]
But it could let's say that the request takes like just the right amount of time to to display before the transition finishes, and so the spinner will show up and then it will disappear really quickly that will get a flash reloading state. It's not terrible, but it's not the best either.

[00:03:55]
And this is a very common problem. This has nothing to do with remix, it's just flush with loading state, like you thought that you were gonna need to show a loading spinner and then the request is faster than you expect it, so it goes away. Flash reloading stays really common problem on the web.

[00:04:10]
And what I used to do back in my AngularJS days is, I would actually to solve this problem. I made it so that every request took at least 300 milliseconds, every one of them. So, any requests that led to a loading state, so that I would never show a flashing of loading state.

[00:04:26]
For my use case, I could argue that that was actually a better solution than the flash, but for what application I was building, but still not awesome. Like, what if the request only took 50 milliseconds, then I just slowed the user down by 250 milliseconds. That's kind of silly.

[00:04:45]
So, what's better is if there was some mechanism for us to say, if the request takes 200 milliseconds, then we don't need to show a loading spinner but if it takes more than 200 milliseconds. Let's show a loading spinner. And if we show the loading spinner, let's keep it showing for at least another 300 milliseconds, okay?

[00:05:05]
And even if we've already finished the transition and everything, that's at least like keep that that spinner showing up. So that is the idea. If you need a loading spinner, then show up for at least long enough that it's not a flash. And that's what the spin-delay is for.

[00:05:21]
And fun fact, this was actually built by somebody that I contracted to help me implement designs on my website his name's Stefan Mayer, and he built this module for my website. And so you can actually see it on if you can make a slower request on my website.

[00:05:39]
Like if we go to the chats page, then boom, there it is, and that was the show spin module in action, or the spindling.. So we're going to use SpinDelay. And I don't know why it imports it as a default, because I don't think it works. You have to do the namespace import.

[00:05:59]
That's kind of weird, but yeah, so import it that way. And then we have some configuration options. So, first we provide the show spinner. The Boolean that we want to have, all that it actually does is it has those semantics I described and you just provided a Boolean and it gives you a Boolean that only changes within those semantics.

[00:06:22]
So, we're actually gonna take this, and assign our showSpinner to that. We're gonna provide that as our Boolean, and then the configuration options, like you can set the min or there it is, the min duration and the, what's the other option? The delay. The defaults are actually pretty good, so, I'm gonna just stick with the defaults for this.

[00:06:43]
So now we come back here, and I didn't like set that up in a way that you could see that demonstrated, but you'll see that like the experience it's still as good the user clicks on something. They see the spinner show up, it's a much better experience than like not seeing anything at all.

[00:07:00]
And still our prefetching still works, so if I wait here for a second and then I click boom it's instant and everything works nicely, so we've just improved the experience slightly by giving our users something to say, okay. Like app is responding, even if they're on a slow network connection.

[00:07:23]
Okay, and this is how you do that. You can put this use transition anywhere. You could have like the little loading bar at the top that some apps will do, like GitHub does that where it's like lying to you, it says like here's the progress and then it gets like to the end and then it just never moves.

[00:07:41]
And you're like, I knew you were lying, you don't know anything. With Server Sent Events, though, you could, you could send them like here's the progress on that thing, it's amazing. It's cool stuff, we can do.
>> This only for like navigation changes or when you mutate things would that transition be updated.

[00:07:59]
>> Yes, yeah so you will get a transition anytime you're using the Form component, if you're using a fetcher form that doesn't count, cuz there's no transition there However, you can get the the pending state with a fetcher. You just use the fetcher itself rather than the use transition.

[00:08:21]
But yeah, for global transitions, that's the only situation where it would make sense to do a global thing anyway, if you've just got fetchers that are doing stuff. You could still do a global thing by using the use fetchers hook. But typically you wouldn't do that, that would all be like local to where it's showing up anyway.

[00:08:39]
So yeah, as usual, I'm long winded in my answers and I used a lot of words to answer your simple question, yes, [LAUGH].
>> What's the difference again, between the dunderapp.TSX and the Dunder app folder? Yes [LAUGH]. So the Dunder app TSX is the parent route, it's as far as the layout is concerned, this is, all of the stuff that wraps all of the components that are inside of the Dunder app folder.

[00:09:05]
So and all of those components inside of there all those routes will show up right here in the outlet spot. So that's why you see this left hand app over here and that always stays the same no matter what page you're on, because the left side is the responsibility of the parent, and all of these pages are children of that parent.

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