Implementing Optimistic UI with Remix
00:00 Let's get optimistic. So we're going to go to our root, and right above the theme switch, we're going to make a function called useTheme. And this is going to manage all of our optimistic UI stuff that we're going to be doing. So the idea here is we need to know what the user is submitting from this fetcher.
00:17 So we can say fetcher.formData.getTheme, right? And it's saying form data may not be defined because it's possible that we're not submitting anything, so we can just add this. And so now we know what the user is submitting, right?
00:35 So this is our optimistic theme, right? So we need to have some mechanism. Here, we'll call this our optimistic theme, right? That makes more sense. So we need to have some mechanism for getting this optimistic theme up into right here to be our theme.
00:54 And so we're going to use this hook useTheme for that. So we need it in here somehow, but the fetcher, where's that fetcher going to come from? So there are a couple options here. We could say, let's move this fetcher up into our app, and then we can pass it down through as props and options and all that stuff. But I don't really want to do that.
01:12 So we're also going to learn another new thing here, and that is fetchers. That's from useFetchers, and it's coming from RemixRun React. And what this is is all of the fetchers that are on the page right now will be returned by this useFetchers.
01:30 And then to find the fetcher we're looking for, we can do a find. Find the fetcher that has form data that has an intent of updateTheme. So come down here, there's our intent updateTheme. So if we find the fetcher that is being submitted with an intent of updateTheme, then we found the fetcher that we're looking for,
01:50 which will have the optimistic theme that we're looking for. So that is nice. We don't have to pipe things all over the place. We can just go with find the fetcher. It's possible that fetcher is not being submitted, and so that fetcher could be null. So we'll add that little question mark right there. And then the other challenge we're going to have
02:08 is anything that comes from formData.get can be a form data entry value or null. And if it's null, we'll just return the regular data.theme, like whatever came from the server. But we need to switch it from a form data entry value into a theme value, because we don't want it to be a file.
02:28 So we're going to just say, if the optimistic theme is light or if it's dark, then we know that they are submitting something, and this is what they want it to be. So we're going to return that. Otherwise, we can simply return the loader data. So let's get our data, use loader data, type of loader,
02:46 and then we can return our data.theme. And that's it. We're done. That's Optimistic UI. Ta-da! So we'll come up here, switch this for use theme, and that gets piped into our theme switcher and everything. So now, if we do a refresh, and let's slow this down, boom. Boom, boom, boom, boom, boom, boom, boom, boom, boom, boom.
03:06 Look at that. It's amazing. Ah! Yeah. Awesome. Super, super cool. And this is still doing the full network and everything. What's actually interesting about this is you'll notice when you click on that a bajillion times,
03:22 like I just did, we're getting canceled post requests as well. So this doesn't actually cancel the request, but it cancels caring about the response. And because we're setting the theme based on that response, then we're just ignoring that cookie. So we actually only set the cookie on this one time
03:41 where the post response comes back. And so this is exactly what we want. The user clicks on this, they're like, ah, actually, never mind. I don't like that. And so we're going to cancel the first one because it never completed, and the user didn't want it anyway. And we're going to let the next one come along. This is awesome because it means we don't have race condition problems.
03:59 And all of that is handled automatically by Remix. It's just so mind-blowingly awesome that OptimisticUI is just so straightforward with Remix and that it's handling all of these edge cases for us. So let's review really quick.
04:17 We have our data that's going to be for the fallback if the user's not submitting something. And then we grab all the fetchers that are on the page, and we find the one that we're interested in, the one that's responsible for triggering this fetch request. And the only reason we have to do that is because we don't have direct access to the fetcher.
04:36 Often, I find that, like, if you're doing, I have an example of a to-do list where you want to have it optimistically checked off. And the fetcher is inside the component where you're rendering that OptimisticUI. And so you don't need to use fetchers. You just say, if that fetcher has the thing, kind of like what we were doing in the beginning here. So you didn't have to find the fetcher.
04:55 So this is actually a more complicated OptimisticUI implementation than what I'm typically doing with Remix. And it's not even that complicated. So we're looking for our fetcher. We find it, and we determine what the user's trying to set. If that is a valid theme, then we return that. Otherwise, we're going to fall back to the regular theme from the data. It's awesome.