Optimistic UI in Remix
Sam Selikoff
Channel
Interviewed Person
Sam Selikoff
Description
The useSubmit Hook just got an upgrade... let's use it to build some optimistic UI in Remix! š LINKS Code diff: https://gist.github.com/samselikoff/1b7d18b0aad30145e2f2a8c899fdf5bc Save 40% on Build UI this week š https://buildui.com/pricing š TIMESTAMPS 0:00 - Intro 0:45 - Removing the pending UI 1:46 - Accessing pending form data with useFetchers 6:30 - Adding optimistic data to the feed 8:16 - Immediately clearing the textarea 10:40 - Submitting the form on Enter 12:44 - Why useFetcher is wrong 14:48 - New API: useSubmit 19:03 - The problem: Race condition 20:10 - The refactor: Client-side UUIDs 29:02 - The solution: Filtering persisted records from the optimistic data 31:42 - Demo 34:15 - Final touch: Saving indicator 36:19 - Black Friday Deal!
Transcript
I've been playing with some new apis from remix for building optimistic uis and I want to show you what I've learned and to do that we are going to be looking at this work journal app which comes from the remix course I just finished but it's a pretty simple app and it lets you add entries I'm recording a video and save them and then they show up here in the list and you'll see uh that we currently have some pending UI here learning one so when we click this we didn't out the form and then we refocus it and clear the input
once it shows up in the list down below and we want to turn this form into an optimistic UI so that I can just add an entry add another one I don't have to wait on the network and so that's exactly what we're going to do and the first step here is to get rid of this pending UI in this form so let's come over here to our index page and we'll see the form is rendering this entry form component and uh this component uses a fetcher to render a fetcher. form and Fetchers are good for rendering
forms without a navigation Great for any interaction that stays on the same page which is why we use this because we are on the index route here and when we save a new entry we don't want to navigate anywhere so that's why we're using fetcher and we'll see right here is where we disable the field set when the fetcher state is not idle so a fetcher can be submitting or loading we disable it and we fade it out to 70% % opacity
let's just get rid of this and we'll test this out and now we don't see uh the form being disabled anymore we still see this saving label so let's come down here and we'll just make this say save and so now our form doesn't have that pending UI anymore and uh if we come here and save it uh we can talk about how to get this new entry to show up immediately in our list of entries right here and how might we do this because right here we're working with this entry form component which we're
rendering here in the index route so how can we get the data from the form over here to the index route well it turns out there is an awesome hook in remix called use Fetchers which is perfect for this so let's grab use Fetchers and I'll just go ahead and grab the Fetchers and log them so we can see what we're working with let's come over here and open up the console
and create an entry and here we're going to see the Fetchers being logged if we look at this first one we see that there's one fetcher right here it has this form data object and the state of submitting and then down here we get to render with loading and then finally we get one with idle so you can see what this Hook is doing it is actually giving us access to all of the current pending Fetchers in our remix app globally here without us having to thread through prop or send any data up from our form we just get to use this hook and access all currently
pending Fetchers right here on our index component so this is perfect because we'll be able to grab the form data from these Fetchers that are kind of in flight and basically append them to our list of entries in the index so let's do that let's actually uh grab these Fetchers and map them and then we can grab the form data from each one and if we call object from entries then that'll give us the data and it looks like form data can be
undefined so let's go ahead and wrap this if f. form data and then we'll return the data here and these will be our optimistic entries these entries come from our loader right here on the server but these will be optimistic entries just like this so let's go ahead and log optimistic entries and uh we'll see what we're working with here so it starts out empty
Video Details
- Duration
- 38:02
- Published
- November 21, 2023
- Channel
- Sam Selikoff
- Language
- ENGLISH
- Views
- 10,764
- Likes
- 405
Related Videos

Avoid premature abstraction with Unstyled Components
Sam Selikoff
Interviewed: Sam Selikoff

Building a Reusable Component that Animates on Scroll
Sam Selikoff
Interviewed: Sam Selikoff

How to share a React Component with the URL
Sam Selikoff
Interviewed: Sam Selikoff

How to build a Recursive React Component
Sam Selikoff
Interviewed: Sam Selikoff