Advanced Remix

Optimistic UI Q&A

Kent C. Dodds

Kent C. Dodds

Professional Trainer
Advanced Remix

Check out a free preview of the full Advanced Remix course

The "Optimistic UI Q&A" Lesson is part of the full, Advanced Remix course featured in this preview video. Here's what you'd learn in this lesson:

Kent uses a TodoMVC application to answer questions about handling multiple UI updates to the same component. Questions about managing fetchers are also answered in this segment.


Transcript from the "Optimistic UI Q&A" Lesson

>> How would we make the optimistic updates apply to other components which depend on the same state to keep the UI consistent?
>> Yeah, that's a super question. Actually, I'm super glad that we're talking about this cuz I kinda forgot to demonstrate something. When we talked earlier about useFetchers, that's the answer is useFetchers.

TodoMVC, anybody remember this thing? I know Mark does, cuz he just rebuilt one in vanilla that was 170 lines of code.
>> Yeah, it was 174.
>> Yeah, welcome to the modern Web, it's amazing what you can do. I also built a TodoMVC with Remix, and this one has a bunch of other features, like login and user, it saves to a database, all the things.

But I also went way heavy on the optimistic UI here. And so if you go to a slow 3G network and say one, two, three, error, four, five, and that error is gonna actually come back. And it's gonna say, hey, this one was wrong, you need to fix that one.

I coded it so that you can include the word error in a todo. So now I can say, okay, well, let's fix that. And then six, seven, error, eight, error, nine, there it is. [LAUGH] And so that error, I submitted two errors this time, right? So I'm gonna fix this one, and that other one came back, too, both of these came back.

And now I can continue with my nine. It's a really amazing experience, and this is one route. Again, it handles user authentication, actually persisting to a database on the back end, taking care of network and all of that stuff in 600 lines of code with all that optimistic UI.

That's pretty rad, and I challenge anybody watching to rebuild this in any other framework and compare it to what I have with Remix. You can find this one at remix-todomvc. And just let me know what you think about if you have feature parity with what I have and compare it to what we can do with Remix with this optimistic UI, cuz it is amazing.

So for all of this, I have a couple of things. Each one of these is its own component, it has its own useFetchers for stuff like checking these off and all of that. And then this parent here, let me actually get rid of a couple of these so we can see the whole thing.

This parent down here, or the parent that wraps all of those in parent component, is rendering how many items we have left. So it needs to be optimistic about how many items are left or that are left to do as well. So when I mark this as complete, even though it takes a couple seconds, I still need to say, hey, how many are available optimistically?

So as I go back and forth between this, we're going to get that number updating, and I use useFetchers for that. So the parent component uses useFetchers, finds all the fetchers that are on the page, and determines what number to show here. It also does the same thing for these filters to know which ones to show optimistically, even if that isn't actually totally complete yet.

So it's pretty cool what we can do with optimistic UI. Yeah?
>> Do the fetchers have names? How do you identify which one?
>> Yeah, so because each one of those lines, I guess I should pull that back up. Because each one of these lines is its own component, then they can all just be specific, or they can name what they do.

So I have a toggle-complete fetcher, I've got a delete fetcher, yeah, all of that that you would expect. So yeah, Mark?
>> The previous question was around more double submit and preventing double submit, and I guess it ties into optimistic UI. If they click twice quickly, how do you prevent a double submit-

>> Yeah, great question. So when I check this checkbox, that is a submit, as is being described. Here, let's slow down the network, and Slow 3G. I'm going to click it, starting in an off-positioning, I'm gonna click it seven times. So it should be checked when I'm done and after all revalidation, everything.

One, two, three, four, five, six, seven. You see in the network tab Remix is automatically canceling the request. Because as soon as I submit a new one, Remix is like, that request doesn't matter. There's no way for us to go to the back end and say, hey, that request, I mean, the Web platform doesn't offer any way to say, hey, never mind on that request, so that would be application code.

But for us, the way that we're building this, actually, it doesn't matter. Because when we do this submission Payload here, we actually just send, what is the state that I want it to be rather than saying toggle. If you sent toggle, then that's your bad. So set it to what you want it to be, and that's the best way to build a nice optimistic UI experience.

So yeah, resubmissions, we actually don't need these requests to be canceled. This is just Remix being a little bit nice to your users and saving them the data. What you're actually canceling is the response, not the request, when you do this. So yeah, Remix handles that for you automatically, which is why I guess I failed to mention it, because you don't have to think about it, yay, cool?

>> What is the formRef.current.reset doing exactly?
>> Yeah, so that is resetting all of the form fields to their default values. So that's just a Web thing, nothing to do with Remix, as lots of things with Remix are just Web things.
>> So we would use the fetcher in the parent and prop-drill the optimistic state to its children?

>> No, so the fetcher will be colocated to the component that needs it. And then the parent can find all of the fetchers via useFetchers. So useFetchers will return all of the fetchers that are active on the page, even ones that are outside of this. And I can just briefly show you how the code works for that in our todos.

Here, useFetchers right here, so I get all the fetchers that are on the page. I filter those down to the ones that we can be optimistic about. There's a semantic around that you can take a look at. And then I filter that down to the fetchers that are responsible for creating new todos, the ones that are responsible for deleting todos, and the ones that are responsible for toggling the state of todos, cuz that's what the parent cares about.

It's like, if there's anything that I could be optimistic about toggling, then now I know what number to show. I know which ones to show and which active or completed or deleted, all that. Yeah?
>> Is this using XState or something similar behind the scenes?
>> So Remix is not, but I believe that there are elements conceptually of state machines in the transition manager, which is responsible for all this stuff.

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