Hands On With Async React
Learn how Suspense, transitions, and optimistic updates work in React with core team member Ricky Hanlon.
Resources & Links
Read the transcript
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
Jason: Hello, everyone. And welcome to the web podcast. We're going to have a great conversation today with one of the core maintainers of React. We are going to be talking about some of the modern features of React that you may not be aware of because, you know, like React has been around for a long time, a lot of educational materials that are one way. If you're not really plugged in you might be missing some of the new features. So please join me in welcoming, Ricky Hanlon. How are you doing.
Ricky: I'm great, how are you doing?
Jason: I'm doing great. Thank you for joining me. I know you have been super busy with a whole lot going on lately. I have a million questions for you, so first give us a bit of background who you are and what you do?
Ricky: I'm Ricky Hanlon. I actually just passed my 7th anniversary on Facebook and starting on React team since 2020. So it is really exciting. I do a lot of tweeting and talking about React. And helping people understand it. So I'm excited to kind of chat and learn with you.
Jason: Yeah, I'm really excited to have you here. Because I feel like I don't know that I feel out of the loop, but I feel like I've maybe seen my own feed around React sort of settle into a very specific kind of cadence. And I guess that sort of makes sense, right? React has been around for 12 years now. And so I guess we could maybe except as a community, that it is kind of matured and settled, right? And like it's is that reasonable to assume that like, you know, React hit its stride and it is baked and done, or more to it than that?
Ricky: I love that I think that is a very shared sentiment, I see people talking about things. That's the one of the reasons I want to get on here and talk about some of the new ideas. I talk about this at React conference a couple of weeks ago, React is like landing more innovations now then we ever have with things of activity and use optimistic, and even the server side features, that not every app needs. But it is, like a really exciting time for me. Because I I've kind of like felt like I've been watching the team build some incredible work and I'm not sure that people appreciate everything that React has now today. So if you watch kind of our talks and our announcements over the past really 10 years, is we have been talking a lot about in the future you will be able to do this, in the future you will be able to do that. This is what concurrent rendering is. This is strick mode for effects thing, yeah it breaks it, but in the future it will make the easier to adopt this thing. Throughout that time there is a lot of frustration, because there is a lot of future promises. Well, we delivered those promises now. And so one of the things I the really trying to get out there and help people see and understand, what is this new world? What are all of these new capabilities, how can you use them to build better apps and better experiences with less code. I kind of did a demo of that at React conference, we will have the PO released on that soon. But just a really, like one of the things I I have been saying is that, I think a lot of the perspective is like, oh, there's this like one API, if have this one U.S. case, I can drop in the one API for, like, Transition(), I can add a Transition() to it make it faster. But if is an end to end different way of writhe your app. All of the features work together. You really have to, what I call async React. All of these features really come down to handling async like requests and gets and posts. And like asynchronous rendering things visibility and not visible. And I want to paint the picture what does a fully async app modern look like?
Jason: I think the best way for me to get my head around it and people not following closely, let's kind of talk through the different pieces happening in the apps. Because from the outside looking in, I have been aware of like two really big things that have been going on in React. I think the biggest one and the one that's been getting most of the attention in the discussions has been React server components. And then the other one is
Ricky: It is a great question, the way I think about
Jason: Okay.
Ricky: So whenever you are doing a get, you can suspend and fetch that data. When you need to get, you refetch in render. You know how to do side effects in render, but allow to define data dependencies in render and use
Jason: Uh huh. Okay.
Ricky: Then we can get into useOptimistic() and how that can help you provide even faster feedback.
Jason: Yeah. So if I'm thinking about this then correctly, the mental model that we want to build is we're sort of thinking about each section of our app in terms of how we would interact with it as opposed to like defining all of our dependencies at the top level and kind of passing the them down through context or props or whatever. Where we're sort of able to think about them almost as like independent little capsules of app logic. And by wrapping things in
Ricky: Yeah, if you take a step back and think about the problems of doing async in client side apps, like just in the history of doing client side apps.
Jason: Right.
Ricky: Like so many cases you have to handle. The user clicks on something, you do a fetch, they click on something else, what are you supposed to do? You fire off two requests. Now what happens if they come in out of order. Then you get the flickering bad experience where like, the page updates with the second request and then the first request comes in, reverted it backwards, now you are going backwards in history. And then you combine that with like mutations. Like fire off a mutation, you fire it off again, those come in out of order, your gets also out of order. The benefits of doing like
Jason: So is this, is this kind of taking over so as, I have built some of this stuff in vanilla JavaScript to see how it works, if I have multiple buttons and be able to click the button, I misclick and click the first button and meant to click the second button, if I quickly click the second button I want to cancel the first button. You have to have, an AbortController, you are kind of managing all of the things being passed around to be able to control the promises unresolved. It is a very like it is not hard, because the APIs are, you know, they are clear. You can use them, but it is a very manual process and have to track a lot of threads going through. You're saying the way this is done, this has done that for me, we are using a Transition(), I have Transition() one and two, if I click one and then accidently did that and meant to click two, it sort of manages the process of aborting signal one and making sure that, like is that, am I reading that correctly?
Ricky: Yeah, yeah. Definitely. The one nuance there is for mutations, we wouldn't automatically cancel the mutation. So in that case you would need to do like an abort of the previous one. But in just the default case, let's say you have three tabs and you click on one tab, it takes a while to load that tab, you're like I didn't mean to click that tab, I meant to click the other one. If you click the other one, React will be like we're not going to wait for the first tab to load. Let's load the second tab, when it is ready it will come in. All of the manual coordination and canceling requests and everything. There is also a benefit there, because you can abort the request, but if you don't abort the request for the second tab it will still like load the data and be in the cache if the user does go back to the other tab, the data's already there, you have already fetched it.
Jason: Sure. Yeah. Okay. Okay. This is starting to click for me and like the amount of, the amount of struggle that you feel when you start getting into these complex apps where everything does load on demand. And user interactions trigger things to load. They trigger things to be mutated. All of that is something, I remember, back in the day, before hooks even, like that coordination was hard. And you had to reach for third party libraries if you were not reaching for third party libraries you were writing one. [ Laughter ] This is one of the hardest problems in modern web apps, the data is coming from everywhere at completely random intervals because it is all influenced by what users are doing as well as now we've got like things coming in on WebSocket, we have things coming in through, you know, in some cases like server push and things like that. That is really, really interesting to kind of think about how do you solve it as the framework level so we as web devs don't have to think about it. This is a question I have. I feel like React is so big and has such wide adoption, I think you get a lot of crap, because any one has opinions what they want it to be. How are you making the choices. You're looking at designing of API around suspense, or designing Transition(), how do you make choices on like what is the right thing? How are you getting feedback on ergonomics and deciding this is the thing that does not break thousands of users apps when the rolls out in the next release?
Ricky: That is a really hard question. I think the biggest struggle, first of all I don't really make those decisions. You know, there's other people on the team that are way smarter than me that think about these things. But you know, kind of following along and looking at it, I think like we start from first principles of like what is the core problem and then figure out how do we solve this, you saw this with concurrent mode. If you go back and watch Sebastian's 2017 talk, he really talks about from first principles. How the React team thinks about performance and broke it down into performance has a bunch of ways you can squeeze down performance and get it small, but fundamentally you need to paralyze things, that's where fiber came from, the first principles we need to break the app into chunks and have priorities for different chunks of work. And so we built that with fiber. Then it is like, okay. Now that we have the app broken into chunks and we can prioritize in a different levels, what what are the different priorities? So we built out like, you know, immediate priorities from like user interactions. And also, also outlined the concept of like three panes. Like the ideal, I think about what is the ideal user experience when they click on something and then they see a result? If you minimize it, there should be no more than first pane, the first pane I click on it I get immediate feedback. Is that possible? This is INP. And immediate feedback. And change the filter, I immediately see the filter that I selected. The second pane is like the busy state. And so, it might be like a spinner, it might be a glimmer, like there's two different cases there. An existing page you want to just show a spinner in line and not like completely, but on new navigations can completely new content, you want to show a glimmer and as fast as possible.
Jason: You're using the term glimmer. I don't know when I heard that before, when I said skeleton component early, is that's what you mean?
Ricky: That is Facebook term, that is glimmer, that is the shimmery thing. And the third pane is the content when it is finished and getting that. What you see manually doing async yourself, you see just a ton. It is interesting because back in the day, doing PHP apps the problem we had there, we had the immediate feedback, if you just use a native select component, that will update that immediately. Then you have no intermediate state. And then you would see the final content, because you're doing a multipage navigation. So JavaScript was invented to solve that problem. How do we add feedback to the user during this intermedial state. So we got JavaScript. Okay. Now, with JavaScript, after you do that select, you can update the page until we load the new page for the full page navigation.
Jason: Got you.
Ricky: You do that with a form component and nonsubmit. So that's first principles. Now how do we design APIs that allow you to do this. That is the hard part. And we it is interesting because like if you look back at the history, remember concurrent mode, it is like, hey, we're going to ship this new thing, a completely different way to write your app, and you have to rewrite everything, and it will break everything, and a huge thing and we went back to the drawing board, we know where we want to go. We didn't know all of the answers, use, async Transition(), and Optimistic(). How do we give people the gradual migration to start adopting these patterns. So that's when we made all of the concurrent features opt in, so if you could adjust them in and use them in specific parts. But it could have been easier to have a new library that worked this way by default. So that's kind of the way that it works. What should what is the like first principles the way the app should work. And how do we create apps for that. Okay. Now we know where we are going, and let's work backward so the ecosystem can migrate to the new patterns. Kind of the struggle now, now, we have everything, you can incrementally adopt it. So how do we get awareness. Now we have 12 years of patterns and knowledges and experts on these patterns that we've had for a decade now and all of these new patterns, how do we get awareness, education material, and explain all of them. A lot of these things are a lot more complicated in the but they are also similar. I don't know how to explain it.
Jason: Yeah, I think, I mean, it's I heard, I heard this described as like a spiral. You know, because it feels like we have an idea and we push towards that idea and then find the limitations of it and then kind of move back towards the other idea, but we got more context, so it is not like it feels like if you're looking at it from the top, it looks like we're going in circles. As you look at it from the side, we are steadily getting better with each iteration, we have more information as we start to revisit ideas that we were missing details about before.
As you, it's not whole idea of like iterative shipping, if you ask people to use a thing, they are going to stay I really like this, but this part was terrible. Okay. How do we do it so they don't think that part is terrible. You kind of keep going. It is just really doing it on hard mode when you have to like release this as you know, arguably the most well known JavaScript library on the planet.
So
[ Laughter ]
I do not envy the role out that you have to do.
Ricky: Yeah, the way that I I kind of put it in my talk is is talking about the innovation window. So if you look in research about how innovation happens, you have this like idea and you ship it and then you have this steep climb of adoption. And then you kind of hit a local maximum of like you got like you have gotten everything that you can out of this paradigm or idea, like cassettes, right? Then you have like a new innovation. But you will necessarily like go backwards. You go back down. Because like new ideas take time to understand, adopt, get buy in, so it gets harder, but then you gradually will like climb up again and hit a new local maximum. So cassettes, the first CD players came out, they cost $2,000, and massive. Right? Put the innovation was so powerful that over time that cost came down. Over time you had CD players in cars. You had, like and then the adoption just took off and innovation was such a powerful idea. We are kind of at that place with React right now. React 16 was good. We could have just stopped there. Right? But these new ideas of being able to handle asynchronous built ins is like an innovation. But even you see this with server components. Like server components are an innovation, but in the JavaScript world that looks like not bringing down costs necessarily, but things like tooling, right? So, we built so many tools around certain patterns then when you have a new pattern, you have to kind of like go backwards in the developer experience, because you don't have the tool for those kind of things. You can see this with server components a lot. But those are solvable problems. And as those get solved you start to go further and further up the curve.
Jason: Yeah. I think that's, I mean, that's a really interesting way to look at it. I think, you know, the you can see that if you look back through the history of React where you can see these ideas emerging years ago, you know. The thing that I think no one default the React team for that you are nothing if not consistent how this should get done. The details of how it is getting done have shift as technology shifts and APIs get tested, but the message around fiber has not shifted in years. And I actually think, wasn't, there was a website called is React fiber ready yet? You just hit full coverage on all of the tests. Right?
Ricky: We hit full coverage when we shipped React 16. That kind of switched everything over to fiber. But the larger I think to your point, though, the larger of like what is fiber unlock and what are all of these new capabilities and things, I would say especially with the 19.2 release, things like activity and the 19 release with U.S. and useOptimistic() and async Transition()s. They built empathy for our team a bit is like, in like 2018, when we were building these things, we didn't know what all of the AIPs we're going to look like. Right? So one of the things I tweeted was like, if we would have shipped nothing for since then and then today we were released like async React with all of these features it would be a lot easier to click and understand, but just looking at the fairy, how we had to trickle things over time, and we had
Jason: It is almost necessarily to do that, but it also creates a really difficult challenge, because when people have an incomplete puzzle, they are sort of force understood reinvite their own pathway to the complete solution. So imagine now a big part of the challenge you're almost working against like user land solutions or userland patterns that help people overcome the things that hadn't shipped yet. Now, like do you find that you have to do a lot of uneducating of like habits and patterns people have, to I guess, that's why were here, to get people to see the potential of doing this new fully comprehensive way.
Ricky: Yeah. Definitely and also the concepts. Over times you had to fill the gaps with API and concepts we had with userland concepts, because the things to do those things didn't exist. Yeah, good example of this is the use API. We're working with some data, fetching libraries right now that are still using throw a promise. But the use API adds a lot more capabilities in terms of performance optimizations that we can add and also developer tools. But you know, we had throw promise for five, six years. [ Laughter ] So and a lot of things depend on that specifically. Type of behavior. So, there's a little bit of like undoing to take that step backwards to take a step forward.
Jason: Okay. All right. And so, I want to get us into, I kind of want to wrap here, but we, so you gave a talk at React conference, if we go to the website, the full day is there, it looks like it has bookmarks in it so you can find where the where your talk is and then the edited talk will drop soon, you said.
Ricky: Yep.
Jason: Ask the same URL.
Ricky: Yeah.
Jason: And then you were talking about the use API and React degree. You can search on there for use and find the use docs. I'm going to drop your Bluesky, which is Ricky dot FM on Bluesky.
Ricky: I'm back on Twitter.
Jason: Back on Twitter. What is the Twitter user name.
Ricky: Ricky Hanlon II. The second.
Jason: Got it. Got it. Let me throw that one in the chat as well. So if you're using, if you're using that one, that is Ricky Hanlon II. All right! Well, thank you so much for taking time with this. And teaching us about it. Super excited to see more of this in action. Any parting words for the podcast here.
Ricky: Thanks for having me.
Jason: Wonderful, wonderful. If you want to see more of this, we are in "Learn with Jason" going to be paired programming, if you want to see us build something with the API look for us. If you like this, like, subscribe, share, do all of the things you need to do. Ricky, thank you for taking time with us.
Ricky: Thanks for having me. Have a good one.
Jason: Don't go anyway, we are going to continue, we are going to do the show in two parts now. We are going to start up the "Learn with Jason" show in just a moment. All right. So, bear with me while I run a little intro here and intro here and then get right into paired programming. ¶ [ Music ] ¶ Hello, everyone. Welcome to another episode of "Learn with Jason." Today on the show, we have one of the React core maintainers teaching us about how the new APIs in React work to do async React. Please welcome to the show, Ricky Hanlon. How are you doing?
Ricky: Hey, Jason, I'm doing good.
Jason: I'm super excited to have you here and dive into the code, before we do that, who you are and what you do.
Ricky: I'm Ricky Hanlon. I am on the React team. I passed my seventh Facebook anniversary. So I have been using React since 2014, so before that, a back end Dev primary, now I have been doing front end for quite a bit now.
Jason: Nice. Okay. So today we're going to talk about async React. And we're not going to go too much into the conceptual part, if you want to see that, we have a web Dev podcast you can listen to and watch we go into the abstract. In this show, we are going to jump into the paired programming. So let me bring up my window here. I'm going to show, here is Ricky on Bluesky if you want to give him a follow. This is the right place to go for that. And then on Twitter you can go find Ricky there as well. Let me throw that up on the screen. All of this are going to be in the show notes. We are going to be talking about async React. Which I don't know why I didn't have your face up here, sorry. [ Laughter ] Which you talked about at React conference. So I'm also going to throw up a link to React conference. You have a full talking about async React and giving people an insight into it. I want to get into the code. Ricky, I want to dive into this, I have new npm create winnow here, what is the first thing I should do to start learning async React.
Ricky: The first thing is build a React doc whatever framework.
Jason: So you said, part of this we need an API, we want to fake that and control it, I know how to do that really fast in Astro. I'm going to do it fast in Astro, that's the one I know. Okay. "Learn with Jason." And I'm going to make a new, or actually I'm going to wait, I want to do NPM PMPN create. It is right there. Astro latest. We will call this one async React. Put this in the middle of the screen. Okay. What this is going to let me do, have an API folder so I can really quickly threw together our get and post endpoints. And then we're going to mount an async or a client side react app right in the middle of it. So that way we have our full client side React app and we can fake an API to try these async features. So let me get into this new project. And then I'm going to open this one up in VS Code. Yeah. That's happy with that. See, we're not using AI today. We're using Ricky AI. So, we so we've got our main index page here. What I'm going to do is, we're going to do PMPX Astro add React. I think that is all we're going to need. Okay. So I'm just adding in React so we have access to writing and running React inside. And then I'm going to PMPN run Dev, that will give us on app, which will be running out here in local host. So we have our extremely minimal app. I will take this to the left half and take this to the right half. And inside of here, we can now start putting together some components. So, you were talking about, when we sort of brainstormed on like a good app to build, you had mentioned that you know, we what these async flows give us is the ability to handle the initial page load as well as user interactions. And so, I thought maybe an easy thing for us to do would be to just create the old classic of either a to do list or a blog roll so we can have some items and add new items to it.
Ricky: Yeah, let's do a to do. The thing we want to show is using async React features for the get and the post. Async requests.
Jason: Okay. So we've got our basic to do. And so the way that I would do this in like traditional React, right? Is I would just get in here and I would import some stuff from React. And then I would export a function called to do list. And I would return, you know, maybe let's call it an unordered list. And give it some list items. And you know, would be thing one and then we could do a thing two. And then out here, I guess we don't even need this yet. We can just leave this out. Over here I would be able to import my to do list. From my to do component. And down here, I can say something like async React. And then we'll do our to do list. And we'll make it client only. We're going with a single page app today. I save this. We get our thing one and our thing two. So let me make those a little bit bigger. So, how should I actually set up our components here?
Ricky: Yeah. I think, I think a good thing to do for the learning aspect is like we need to get some requests in here to fetch some data and add to do, so we need posts. Why don't we start using it, how would you build this if you didn't know anything about the like new React features?
Jason: All right. Let me put together
Ricky: I mean hooks. React Dev.
Jason: A prehooks React Dev.
Ricky: No, 2016 post hooks.
Jason: Okay. 2016 post hooks. Let me really quickly, we will do a post dot TS. I think I can copy this out of Astro docs and that way we will have our APIs running and won't have to look at them again. Where are my docs at? Astro. And then we're going to go to actions and not actions. To endpoints. There we go. Then I want probably just make these static for now. So get one of these. So that's going to be our get. And this one honestly we don't need any of this. So we can just return a new response that is going to have we'll do to dos, and that's going to be an array in each of these, do we need IDs or anything like that, or just send back text?
Ricky: You probably need an ID and text.
Jason: Okay.
Ricky: We're going to probably be adding to this over time so we can hoist that, too.
Jason: Oh, yeah. Good call.
Okay. So we'll get one of these. Okay. So, that will be our deal here. And we're going to respond with our to dos, but what we can potentially do here is just like await let's see. A simple sleep function that I always forget. So basic sweep.
We're going to give it a milliseconds and default to thousand. I got I'm on my fancy keyboard, that means I don't know how it works. So
[ Laughter ]
we're going to say return new promise stop, whatever you're doing to help, you got to stop it.
And then, we're going to send a resolve. And we'll say set timeout. Resolve true. And the timeout is going to be whatever the milliseconds are. I have gotten this wrong somewhere.
Ricky: Async function.
Jason: Oh. Right. Right. Right. Then I'm still missing.
Ricky: You can see those things. It is like
Jason: Here is my setTimeout(). And that's going to resolve
Ricky: Milliseconds were correct before. But using parentheses instead of brackets for the
Jason: Oh, right, right, right. Yeah, you're right. So this then needs to be with these. These. Those. That should be. There we go. All right. Now, what we can do, we should be able to just await, sleep, and give it whatever amount of time. So we'll say this takes half of a second to load. Or actually, because we want this to actually show up, we will make this three seconds to load. And then we're going to
Ricky: Do you need to stringify() those?
Jason: Yeah. That's what I'm doing, stringify() this. Okay. Now we have the ability to get these. Which means out here we can fetch them. And so, in order to fetch these, I would do something like to dos and set to dos. And then I would grab use state. And then I would set this to like an empty array to start. And then I would do something like use effect and inside of this use effect, I would have it say probably, we need a function to do the fetch. Right? So we need an async function yet to dos. And this is going to be result equals await, fetch and this is what was it? Going to be API posts. And that doesn't need any details. And then, we'll say that to dos is going to be JSON, we are going to trust that works and not do air handle, because why not.
Ricky: That is a promise.
Jason: Is in fact a promise. We are learning I forgot to code today. So in here, we can run get to dos. And in here, we can to dos dot map, that's going to give us a to do. And then, we can put out one of these, give it a key of to do ID and a value of to do dot text I think it was. Yes. Okay. And you're unhappy because why?
Ricky: We haven't typed our to dos.
Jason: Okay. We have not. So then this here would be array of ID number and text string. Did I do that right?
No. Array. Okay. Uh huh. Okay.
So
[ Laughter ]
Now, that I kind of remember how all of this stuff works, that theoretically means there we go. We're getting our thing.
And so then we can, we can expand this to include a complete.
All right. We will say false. And then out here we can expand, I should probably put this type somewhere else. But and in here, we can put this to have a checkbox. Just to make this really easy. We will say input type check box and we'll say checked equals to do dot complete.
And why are you unhappy? Must have a label. That you, it is fine.
This is kind of gross, but yeah. Whatever, that's fine.
[ Laughter ]
Stop yelling at me.
So, this then is like kind of doing what we want, but a controlled component, so we don't have the ability to actually update it. So we would need to write an on change. You're nodding. I realize I'm kind of like running away with this one here.
Am I going in the right direction. Right?
Ricky: Yeah. This is great. No need to post endpoint to actually mark it to do on the server.
Jason: Okay. So let's add that. We will export async function post and that one is going to allow us to await sleep and we'll maybe do nice and fast for this one. But then what we're going to do is we're going to take in the, what are we getting this? Do we get
Ricky: The ID probably.
Jason: Yeah. It sends in, I can't remember what it sends in. Dynamic routing. Where is my post at? It is going to give us the request. The request is going to have the body of some
Ricky: Do they have a post example on here?
Jason: Yeah. They do. There we go. So we get the request. And then the request is going to have, it bits in it. Somewhere down here they should show an actual example. And the request is going to come in as JSON. So the body is JSON and then get, great, over here. So we can get the request. And then we'll get the body out. Here we will say body equals await request JSON. And then oh, because we have to do this way to get it to type properly. Oh, then it needs to return a response of some sort, that will make it valid.
Ricky: You also need the async in your function.
Jason: Thank you. Okay. So, our response for now can just be something like okay. And that will let me validate. Or, actually, let me do this, make sure that we're actually sending through what we are thinking we are sending through so I can be sure that I'm writing code that works since that seems to be questionable today. So, say async function marked complete. And that's going to take the the ID, which is going to be a number. And then, that is going to take a wait, fetch, that's again going to go to API post. But now, it is going to be method post. And it is going to have a body of JSON stringify() and pass in B here. When we get that back, we can console dot log. Okay. So, then down here each of these would get a on change. Right?
Ricky: Uh huh.
Jason: And we are saying marked complete and pass in the to do dot ID. You're unhappy, because that needs to be one of these. Okay. Why isn't this wrapping? I feel like my autoformatting is betraying me right now. So then we have what should theoretically be the right components in place, so when I click this button we should see the ID logged. No. Post unexpected token.
Ricky: I think when you're posting you're not passing the body stringified(). Oh, you are. Hmm.
Jason: Okay. So what I have done, unexpected end of JSON input. So let's look at what I just did. And we're going to try this again. There's our async thing happening. I'm clicking, it fails, and it fails because we sen through the ID and the response is a syntax error. So my syntax error must be, an API route, an async request, we return a new response that is stringified(). What am I missing? Let's see, maybe there is something in here that we unexpected end of JSON input. Ah, not available in static endpoints, that's what happened. We will export, cons, rerender equals false, now this thing should work. That three seconds is going to kill me. Console is not defined yet, I was halfway through debugging and did nonsense, that is fine. We're going to turn this way down when we write this, let's make this 500. Okay? Okay. So, that
Ricky: Check the console.
Jason: That is logged. And then click the other one.
Ricky: But there is something here, if you go back to the network tab. I don't know if you noticed that you're firing off a lot of post requests.
Jason: Oh, I am. These are all the fetches. Right? So, oh! Uh huh! You saw this and didn't fix it for me, didn't you?
Ricky: Correct. [ Laughter ]
Jason: Okay. So, one of those.
Ricky: Now, we hit 28, like we immediately hit one of the bigger frustrations with React right now which is effects and getting your dependencies right and the spoiler for later is that we're going to not need this effect. So you won't have to deal with this in the async React world.
Jason: Okay. Excellent. We got that.
Ricky: I should have called that out a long time ago.
Jason: Yeah, thank you for paying attention. Then we need one more. I'm going to copy/paste this. Oh, yeah. We'll fix this as well. But this one this one is going to be or this one should actually be put, shouldn't it? Or patch. Patch. Patch or put? What am I thinking? It is put, right? For modification?
Ricky: No. But would be a whole resource update. A patch would be a partial update. But
Jason: So we'll, we'll use, just so that I can keep the same route, we will use patch for marketing it complete and post for creating a new one. So in this one, the request that we would want is we would want to send through, lets me change this one to patch. And just make sure that still continues to work. You got to get out of the way. Okay. So that's still working. And then we're going to have one more which is going to be create to do. And that's going to require whole to do item, which will have the same type at this. Which I will pull out for the sake of here we go. Let's see. We need type to do item. And then down here, we can say to do, which is our item. Which is going to be to do item. And this one is going to be a post. And we're going to put in the entire item. So, what we expect out the end of that is that it's going to give us the whole thing and then I'm just going to wrap this in fragments so I can put things side by side here. We will put in a quick form and give it a label of add to do. Input type. Text. We'll give it, I don't know if we need a name, but I will give it a name of text. And then we'll we need an initial value on this, I think. Right? What's the starting value? Default value. It is just going to be an empty string. And then down here okay. So then this, what we want is an on submit. We're going to run create to do. And we need to do that with actually, why don't we do it this way. Because then we can just use the form input. That's going to be the event. And then we'll get the, the form data is going to be event dot target dot form data. No. No. New form data. Of the event. Target, current target. Is it just the event? No.
Ricky: Yeah, it is event dot target.
Jason: Okay. So then that should give us the constant. Text is going to be equal form data dot get text. That's actually our whole thing. So we're going to not going to be a to do item, in fact, it is going to be the text. And we can determine everything else from here. So to create a new post, we're going to do the ID needs to autoincrement. So we're going to do ID is to dos length plus one. And then we want to put in the text, which is going to be the body dot text. And then complete is going to be false. And that should give us a functioning new to do item, which we will drop in here. And then assuming I did all of that right submit. No, submit event. Don't give me that. No. You? No. This is not what I'm here for. I'm not here to be good at TypeScript. Okay. So, this then this void is not can I just I don't care. This is going to run without this. Right? So, theoretically speaking then, if I say get better at TypeScript. [ Laughter ] And add this, it should, it just full submitted, we didn't prevent default on it. So I can start there. And dot prevent default. And try that one more time. Get better at TypeScript. Then it submits. It gives us a new ID. It marks it as complete false. Okay. Great. Now, we should be able to actually do this stuff and make it all work. So we're going to say to dos dot append.
Ricky: Push.
Jason: That the one I was looking for. I was like why push that item. Okay. And then here on the patch we need to we're going to say constant item equals to dos dot find, and we'll say T dot ID equals dot ID. And then we're going to item dot complete equals dot complete. We will just make it a toggle.
Ricky: Is it a triple equal.
Jason: God, I'm dot compete. Fine. Gross. Okay. So, then, what's not going to change here is when I click this it should update this thing. But it is not going to show anything, because we're not refetching.
Ricky: Right.
Jason: So then I need to figure out how to make it refetch. So that I would reach for what? Like a dirty check? And just like check dirty to true so it refigures the effect?
Ricky: That a great question. There are a lot of different ways to do that. You can do that. You can also fetch in the event.
Jason: Fetch in the event. Oh, yeah. Good call. So I can just down here.
Ricky: So, just thinking ahead, I would do like maybe dirty flag.
Jason: Okay. Dirty set dirty. And then let's use state. And that's going to be false.
Ricky: Do a counter. That way like it will dirty.
Jason: Okay. And then we're going to make the dirty check part of our use effect. And then we will set dirty to
Ricky: Like a update or C, CE plus one. D plus one.
Jason: Just copy that between our create to do and marked complete so we can then theoretically speaking get better at TypeScript. That's it. And then we can say, okay. So, like we're getting there. We're getting there. We have a functioning app. It is a little bit Jahnke. You can see there's stuff that I don't like about this. Like when I do a thing, it doesn't immediately
Ricky: Increase your sleep to like two seconds so you can really show that problem.
Jason: Yeah. Good call. Go here. Okay. So these are going to take, I'm going to keep the get a little bit faster. But so, get better at TS. And it just sits. Then it does show up. And then the same thing happens when I click. Like it's eventually working, but I have no indication that worked, which I didn't know that I put that long sleep in, I would be sitting here going what the hell is going on. I'm just triggering a ton of additional calls. If I clicked an odd number of times. It is going to look like I didn't work. [ Laughter ]
Ricky: And some other problems, right now we're doing just a constant sleep time, but random sleep times we would be able to show raised conditions here of things being like toggled in the wrong order and things like that. Getting that to repro is probably hard. It is one of those education cases that
Jason: Yeah, but we should see things kind of like popping in? Very, very chaotic when you do it that way, right?
Ricky: Yeah, we're not canceling. So these are all queued up. You click a bunch of times, you saw that after you stop clicking, it is coming up.
Jason: Yeah. So I think this is, so we've kind of demonstrated like I hit a lot of stumbling blocks. I have written a lot of React code. And this is a mistake I make every time. I always forget to get my use effect right. I always screw up the little things that cause me a lot of pain. If I'm not using an API that is simulated, it is fast enough that I'm kind of like, oh, this is probably fine, I can probably ship this. Then it is not fine. Right? You have a slow day and it ends up being pretty rough.
Ricky: Yeah, one thing, I think we should add, one more thing and then convert this to async features. And the one thing, when you add a to do, and even when you mark complete, we don't have pending things, we can do that in this world. A lot of the story here of writing an app like this, you can do it. Right? Add is pending. Set it. Clear it when it is done.
Jason: Do you want me to do this?
Ricky: Yeah.
Jason: Okay. Pending. Set pending. That's going to be use states. False. And then we could also do this for like like on a per component basis, like a per to do item basis.
Ricky: We will do that with useOptimistic() later. Because it is much easier.
Jason: Okay. For these we will set pending to true. Same thing on it this one. And then when we get to to dos, we will set pending to false.
Ricky: Oh, that is interesting.
Jason: Because we are kicking off a new fetch, that would be where I would assume I would do that.
Ricky: Yeah, that's going to have a bunch of bugs with it. But the other way has a bunch of bugs with it, too, the other way people typically do this is, marked complete or create to do. You set it to true before you do the submission and then set it to false.
Jason: Yeah, right, right, that is smarter. Let's do it that way, start is at the top, await everything, and undo the damage at the bottom. So yeah, that makes more sense. Down here, the same thing here. That one is going to be true. And then down here, we will set it to false. And I guess, in here, we'll say something like pending and we'll just return that should work. My autoformatter is broken. So I must have prettier configured probably or something. But as we do this then okay. Gross. [ Laughter ] I like that it comes back and still takes time to fix it. [ Laughter ] Good. This is good.
Ricky: Yeah. Let's, let's move the loading state up to outside of the list. So the list kind of states there.
Jason: So the list stays there.
Ricky: Yeah, we don't want to unmount the list while it is pending. We just want to show loading feedback. Maybe above the form. Let's do like
Jason: Yeah. I can do that.
Ricky: Let's do it below the form. Because this is going to shift content down. Or below the list as well.
Jason: Okay.
Ricky: So now, this is interesting, because we now have the loading state while the mutation is in progress. But we don't have the loading state while the fetch is in progress.
Jason: Uh huh.
Ricky: So it is not this continuous loading state. You want with the three panes. You want to loading state to start as the mutation starts. You want to be completely present until that final pane. And then one pane you write it. We can fix this. It is very similar to what you were doing with the app setting it to false after the effect. But it gets very complicated. Even that will help bugs.
Jason: Like I'm already looking at this and thinking god if I had to come back and maintain this later, what a mess I have made.
Ricky: Right.
Jason: You know, this is a really simple example. You just, it just feels like I caused myself a lot of pain in these situations. I guess in this case we don't even need that response. I don't, I don't want, I don't want to suffer for writing these sorts of things. And like this is a complaint that I actually made. I had conversations with like Dan about this, where use effect has always been something that when I'm writing with it, a lot of times I feel like I'm like fighting my own like muscle memory as somebody who has written JavaScript for my entire life. So take your JavaScript knowledge and put it on a loop d loop, you have to track how many loop de loops you have done to do this properly. So how do we fix this?
Ricky: Let's get rid of the effect. So first thing we want to do, we want to do our data fetch and render with use. To use you need to, use you can think of like await on the client.
Jason: Okay.
Ricky: We can not just use awaits, in server components you can just await the effect. But for JavaScript reasons we cannot support that on the client yet. So let's do a cache. Let's create a cache. So constant cache equals new map, and cache this by key.
Jason: Okay.
Ricky: Okay. And then, let's do a constant fetch data. Let's
Jason: This is like an async function?
Ricky: Yeah, that will be an async function. Let's give it a URL as a key.
Jason: Okay.
Ricky: Okay. Now, if the cache doesn't have that URL in it, let's do fetch for the URL.
Jason: So I'm saying constant
Ricky: I would just do if cache not has URL.
Jason: If cache dot has URL.
Ricky: Yep.
Jason: Then we're going to constant res equals await fetch URL.
Ricky: Dot then response, dot response to JSON. Cool. And then cache dot set URL that won't be the data that will be the prompt us. You don't want to await the fetch here.
Jason: Oh, we don't want to. Okay. Got it. I'm going to call it P. Cache dot set and URL and P.
Ricky: Yep.
Jason: We want it to be a promise in the cache.
Ricky: Yep.
Jason: Got it.
Ricky: And then return cache dot URL.
Jason: Okay.
Ricky: Now, for our to dos, instead of
Jason: So do I not want this to be async then?
Ricky: Correct.
Jason: Okay.
Ricky: So now, instead of storing our to dos in state, we can just do const to do equals use, fetch data, with the URL.
Jason: And our URL is API post. And we want to grab that, drop that out. And actually, I want to take this. So we don't break everything else. Okay. Now we got, we don't need the get to dos anymore.
Ricky: Right.
Jason: And we don't need the use effect anymore. Which means we don't need the dirty check anymore. Right?
Ricky: Uh huh.
Jason: I can drop out my dirty check.
Ricky: Let's delete that pending as well. We're going to use the Transition() for the pending.
Jason: Get the heck out of here, look at how nice this is.
Ricky: We will need something to figure a refetch. We can talk about that in a second.
Jason: Okay. We got our to dos. If I save this, does this just work? No, because I have something missing down here. All right. Okay. So now, we've this immediately already, I feel far better about. Like, this is what I have always wanted in React. Right? Because this is how I think about code. I would just, you know, await it. But you can't do that in a component. So there is always this sort of loop d loops. So thank you for fixing my loop d loops.
Ricky: Yeah. So now, one thing that we can use now is
Jason: Okay.
Ricky: Because you need the
Jason: Then do I want this, to be, thinking about the app experience, do I want to wrap the entire thing or just wrap this list?
Ricky: Just the list. Yeah, so actually
Jason: So let's pull this out and we'll call this one to do app. And then we'll come back out here and change this to to do app.
Okay. And then U we're going to get function to do list. And that's going to return our to dos here. So we can hoist this up. Right? Move it here. I guess. Okay. So we got that. And then, down here each of these is going to start living, let's see, we'll have U up here instead. Okay. And then U down here. But we want to wrap this in
Ricky: Uh huh.
Jason: Okay. So, we do a
Ricky: You need a fall back.
Jason: But it already nice that we get this before this shows up. So it's, you know, it's like baby steps. Right? But so then to do a fall back, I whoops.
Ricky: Yeah.
Jason: Just add in a component. Right?
Ricky: It goes to one of the points we were talking about on the podcast. It not just being about it making it easier to show loading state. We've segmented our app into a different segment with
Jason: I think what I love about this is that the thing that made me choose React back in 2014 or '15, whenever it was I built my very first apps. I looked at it and each React app felt like these collections of tiny apps called components. If I could see the component, then I know that is how things worked. It was very easy to compose apps because the components all fit together and did the thing you expected. This brings me back to that. Like knowing that this is all of the the, like the component is here, it has all of the logic in it. This just tells React, like, hey, you can keep running even if this thing, this thing cannot break the rest of the app by making it load slower or making it jump around. I have full control, do this instead, until this is ready and drop it in, I'm back to thinking in components. It is just a very nice experience.
Ricky: Yeah. It feels like more Reacty then our effect version.
Jason: Yes. I love it.
Okay. So, we got
Ricky: Yeah. If we wanted it, we could have like like a glimmer instead of just showing loading. But yeah. This is great. Now, we can fix our mutations.
Jason: Yes. So which one do you want to do first? The marked complete?
Ricky: Let's do the add to do first.
Jason: Okay.
Ricky: So here we have a create to do. This is similar to the dirty thing you wanted. So what we need is after we create, after we do the fetch, let's move this down. Because I think it will be a little bit easier.
Jason: Move this down into like move the form into its own thing?
Ricky: No. Actually, let's do the complete first. Sorry.
Jason: Okay.
Ricky: I want to show how easy this is. Let's go up let's add some state.
Jason: Okay.
Ricky: There is a lot of different ways to do this, now we start getting into needing a data fetch library solution, but I want to show a very simple way to do it. So to do promise.
Jason: Okay. To do's promise.
Ricky: Set to do's promise. You state use an initializer.
Jason: Okay. You have to walk me through that.
Ricky: Yeah, just pass a function there.
Jason: I got you.
Ricky: And then move your fetch data request into there. So what you're going to do is store that promise in state.
Jason: Okay. I'm not using this anymore?
Ricky: Nope.
Jason: Okay. So this goes away.
Ricky: Okay. And then we're going to use like const to do equals use to do promise.
Jason: Got it. Okay. Okay. That makes sense.
Ricky: Let's move that to dos promise up to the parent component. And pass it in as a parent.
Jason: Okay. Okay. And then we have to grab it out here. Which I'm not going to bother to type. We're going to explicitly say any. And everybody hush. Did I spell this wrong? Use to do promise, why are you mad? Oh. I know why. Because I am bad at TypeScript.
Ricky: Oh, yeah.
Jason: Okay. Everybody can yell at me later for that. Okay. So we got our to dos, and our to dos promise, we can see functionally nothing has changed.
Ricky: Now we what need to do in the marked complete, after we are done marking it complete, we need to trigger a refetch.
Jason: I need to set the to dos promise in here as well.
Ricky: Yeah, let's call this a refetch or refresh. So let's create a function. No, let's keep that the same.
Jason: Okay.
Ricky: Let's create a new function coffled refresh to dos.
Jason: Is this async?
Ricky: No.
Jason: To dos.
Ricky: And state. Fetch data.
Jason: Set, like like this here?
Ricky: Yep. Then we have to do one other thing, which is to clear our cache. Otherwise this will just immediately reuse the same cache. So
Jason: Cache delete.
Ricky: You can probably just equals cache equals new map.
Jason: We might as well make it easy. Because that way if we were to use this for something else, it won't blow everything away. And then I can down here just pass this to my to do list as
Ricky: Yep.
Jason: Okay. Then up here, we got our fresh to dos. Okay. And that didn't work because why? Oh, because you don't, shouldn't be here. There we go. We have our fresh to dos, and when we mark complete we just run that.
Ricky: Yep.
Jason: Theoretically speaking, this is everything we needed. Right?
Ricky: Now, does it work if you mark something complete?
Jason: It does. After a fashion. [ Laughter ]
Ricky: So now, let's let's have this feedback. Like when you click now in the app, when you click complete there is no feedback of what's happening. So let's use a Transition() for that.
Jason: Okay.
Ricky: And the best way I would say we should do this is we should have a to do like item component. So that we can show a pending state on the, like on each individual item that you're marking complete.
Jason: Okay. We will get this is going to have ID. It is going to have the text. And it is going to have the complete state.
Ricky: You probably just pass the whole item in.
Jason: I guess that is probably easier.
Ricky: That way if we add any fields to it, you can
Jason: Will start by duplicating what we got, which is to throw one of these out here. And we're not going to have a key on this. We will have a key on the component. So it is going to be
Ricky: Yep.
Jason: We will just call it to do, that's going to make my life easier.
Ricky: Yep.
Jason: Make everybody real mad. Do I need to pass in the smart complete or move it up?
Ricky: You can move the marked complete down.
Jason: I guess we will have to pass down this refresh. To dos. But that is okay. So then down here, we've got our to do item, that is going to get a key. It's going to get the to do. And it is going to get refreshed to dos, which is going to be refreshed to dos. Do one of these. And that should do it. Yeah.
Ricky: We didn't really change anything else. So to refocus on the point what we're going to do is when you, in the app click on one of the items, there's nothing happens. Give it a second.
Jason: Oh, I double clicked it because I thought it was broken. [ Laughter ]
Ricky: So let's fix this. Let's add some feedback. And the other thing that happens is like while we're doing the fetch, you notice that it shows the
Jason: Is pending. Start Transition().
Ricky: Equals useTransition(). And then in marked complete, at the top of marked complete, before the fetch, let's do start Transition().
Jason: Any arguments?
Ricky: Pass in an async function.
Jason: Okay.
Ricky: And now you can move everything else inside of there.
Jason: All of this?
Ricky: Yep.
Jason: Okay.
Ricky: For our pending, how do you want to show the pending for each one. Maybe at the end of the item we will have a dot dot dot.
Jason: Okay.
Ricky: Maybe make that a span. It is pending.
Jason: Right. Right. Right. Okay. So now I don't know. What have I done.
Ricky: You haven't done anything. You are not using the React compiler. There is a nuanced bug here.
Jason: Okay.
Ricky: Wait. No it works. Right?
Jason: No. It is like not updating for some reason.
Ricky: Do me
Jason: There it goes, but it is still doing the thing.
Ricky: So it is still doing the thing, so the to do item is not memoized so when you set no that would not be it.
Jason: Did I screw us going with like a regular like app or something?
Ricky: No. Can you click it again?
Jason: Refresh to dos. Kicks off the whole thing again. Right? So, there's kind of no way for us to not kick off the
Ricky: Yeah, but it is in a Transition() so it should happen in the background.
Jason: Oh.
Ricky: Let's figure how we can see what is going on under the hood in React. So can you check to see what version of React this is running?
Jason: Yeah.
Ricky: 19.2. Perfect. Okay. So go to the performance tab in the DevTools. And just start recording. And then mark one is done. Done. Okay. Stop. Let's take a look here. So make it full screen. Okay. Now, there's two timelines here in the track. So one is called scheduler, one is called components.
Jason: Uh huh.
Ricky: So expand the scheduler. This is one of the features we shipped in React 19.2. These new tracks are showing you what is going on under the hood in React. Can you increase command plus to increase the size, and close the sidebar with the insights. Yeah. Okay. So let's expand the interactions. So let's find your click.
Jason: Okay. So we kind of see our so there's the click. Right?
Ricky: Yeah, I think this is a bad recording. Let's try recording it again.
Jason: Okay. So, clear. Record. Click.
Ricky: Yeah, let's check this out.
Jason: Okay. So what got here's, there's the click.
And then here's where we end up
Ricky: Can you zoom in to that suspended?
Jason: What a great question. Do I just like
Ricky: Yeah. That works. And collapse that bottom bar there. Okay. And then in the components track, you can see which ones are rendering.
Jason: My components track is empty.
Ricky: There are there, you have to zoom in. You can decrease the time in your server and then redo it. The suspended block is making it hard to see the tracks.
Jason: Okay. Let's take all of these
Ricky: Like 50.
Jason: 50. And then take that one down to 50. And this one down to 50. Okay. Clear this. Start the recording again. Click the button. See that time it didn't work at all. Okay. So this is the one that worked, I believe.
Ricky: Yep. So let's zoom way into the beginning of that click. You can actually like scroll in and out.
Jason: Oh, I see.
Ricky: Yeah. So okay. We want to see, so in the scheduler track there, you can see scheduler, and blocking, transitions and it is idle. So you may zoom out and zoom back in to be able to get to the beginning.
Jason: Okay. So we got our I got to get way in. I see. Okay. So we got our to do item, to do item, to do item. So scroll left. This is hard without driving. Sorry.
Jason: Yeah, I guess we should have set up the ability to have you control.
Ricky: Yeah. That's where you want. Over here.
Jason: Here?
Ricky: Yeah. Zoom in and see what's happening there. In that blocking lane.
Click on that update. And then expand the bottom panel where it says summary. Oh! Yeah. That should be in a Transition(). Click show ignore listed frames.
Oh. Fuck.
[ Laughter ]
Ryan is going to think this is so funny, because I saw Ryan in the chat. So I know know what the issue is, the reason the
Jason: Like this.
Ricky: It doesn't need to be async.
Jason: So it can just be like this then?
Ricky: Yeah.
Jason: Okay.
Ricky: Now our issue should be fixed.
Jason: Expect I seem to have created a race condition in here somehow, where it only updates sometimes. It fixed the problem. So I think my bad logic around the post does and doesn't work is kind of not the issue here, but that works. I like that.
Ricky: Yeah, but the pending state should stay all of the way through. Can you click. Yeah. It doesn't okay.
Jason: Yeah. We're back to really fast. Let me turn these up again. Wow! What was that? 500. See that first, yeah, something I did here on that first one it like doesn't work. And then everything is fine. I'm going to assume that's my bug. Since we kind of faked our API. This is great. So yeah. And it does stick through. You can see that the pending state kind of stays with us.
Ricky: So one thing now is like it is kind of for this use case it is kind of like well maybe we should do the add to do next.
Jason: Okay. And we are, we are a little bit over time. So we'll want to kind of get cooking on this.
Ricky: Let's just do the Optimistic() update. So in the to do item, we're showing the pending state. We want, when you click it, it looks like it is done. Right?
Jason: Right.
Ricky: So instead, let's delete this is pending.
Jason: Get like the whole thing.
Ricky: Yeah, let's do, let's just change is pending to Optimistic() complete.
Jason: Okay.
Ricky: And then set Optimistic() complete.
Jason: Here?
Ricky: Yep. And then use change use Transition() to use Optimistic(). And pass in the value that we want it to complete to, which would be to do dot complete.
Jason: Okay.
Ricky: Great. And now, our start Transition(), let's import that from React. And then the beginning, before our fetch, let's set the Optimistic() complete. Set that equal to not Optimistic() complete.
Jason: Okay. So a quick question because this is very interesting. What why would we not import start Transition() from React and use Transition() instead? Like that was kind of an interesting thing that just happened there?
Ricky: Yeah. So useTransition() you can think about it as a convenient layer doing a pending state. So, useTransition() gives you is pending, that is implemented in useOptimistic(). Now that we're doing our own Optimistic() state. We don't need there is pending state. We can go down. I'm not quite done yet.
Jason: So I remove it entirely.
Ricky: We don't need a pending state. We're doing an Optimistic() state. So, the pending state is Optimistic() complete. And one other thing you'll have to do, in marked complete, yeah, that works. All right.
Jason: We're happy.
Ricky: Yeah.
Jason: Okay.
Ricky: Now, if you go in the app.
Jason: Look. We can see as these are going here, I think we will see it here. Right? Like
Ricky: Yeah.
Jason: The pending. That's, yeah, I in my, that's nice. Like that feels like what we expected the app to do.
Ricky: Now we're at a better state then where we were with our effect example at the beginning with less code. Less conditions.
Jason: This feels clean to me. Like this, this is what I want the code to feel like. Right? I want to be using the to dos down here. Like I want to just say, my to dos are this. And obviously up here, we're doing the the like kind of generating a promise thing, but this is really nice to be able to do an async operation here. And not have to do the mental gymnastics of getting the effect loop right. I really like that up here I can, I can decide what happens when, because like I can run some logic on this if I wanted to, where I could set a whole bunch of details about what is happening in the UI based on this. So if was like a list, on add a new to do item, we can compend a new component to the list and then, and then handle all of that. So this just feels like what I wanted the effect flow to be. This sort of feels like it sorts a lot of those problems out for me, which is really nice.
Ricky: And then one last piece is that with this pattern now, we can kind of, because one thing that's not great is having to do this start Transition()s and set Optimistic()s and oh, you got to remember the start Transition() everywhere. But we can have an async React first check box component. So if you take your input, type equals checked down below. Let's just take that and put it into its own component. And call it async input.
Jason: Do I mark it async.
Ricky: No, a function, async input. Okay. It will accept two props. And it will be the value and then we're going to be a passive prop called action.
Jason: Let me get this mark up out here. And then replace this down here with our async input. And that's going to need the value. Which will be
Ricky: For this value, you're going to pass it to do dot completed.
Jason: Okay.
Ricky: And that marked complete. But let's rename marked complete as like complete action. I will explain why.
Jason: Okay.
Ricky: Cool. Now we got to move some other things around. First we're going to need to move this Optimistic() complete down.
Jason: Okay.
Ricky: Let's just do Optimistic() value. Let's call it Optimistic() value and pass the value in.
Jason: Okay.
Ricky: And then
Jason: That got weird.
Ricky: Yeah.
Jason: Okay.
Ricky: Right. So
Jason: This is our action now?
Ricky: Not yet. So create a render. Let's just call that handle change. Because it is an event handler. It will change. Now, take your, do a start Transition(). We're going to do, we're going to transform this event handler into an action. So let's do an async function.
Jason: Okay.
Ricky: So we need the new value. So we need the event target.
Jason: Okay.
Ricky: So let's do set Optimistic() value, and then target dot value.
Jason: Okay.
Ricky: Now, let's do await action.
Jason: Just going to get you to be quiet. We are await action
Ricky: That's it.
Jason: I don't have to do anything with it.
Ricky: No.
Jason: Okay.
Ricky: And then down below, you need to pass the handle change.
Jason: Okay. So where did we get our ID from now?
Ricky: In the action, in the to do item.
Jason: In the to do item, in the action. Now, we are
Ricky: We can clean this up. Before you do that, when you called handle change, you may need to call that a function.
Jason: Oh. Right.
Ricky: Okay. Now, in our complete action.
Jason: Oh, crap, hold on, we have to do like this because we're passing the event.
Ricky: Love it. Now, let's go to the complete action.
Jason: Complete action.
Ricky: What we have done is wrap it into a Transition(). And the action suffix tells us it is already inside of a Transition(). So we have top level start Transition().
Jason: Okay. This one goes away. This one goes away.
Ricky: We don't need to set the Optimistic() complete, that is being handled by our async component. Let's do one last thing. Remove that start Transition() from refresh to dos.
Jason: Okay.
Ricky: And down in your refresh to dos function, where is that?
Jason: Refresh to dos.
Ricky: Line 786. Okay. Let's wrap that state update in start forgot.
Jason: This one.
Ricky: What a data fetching library would do for you. You need that to be a function.
Jason: Okay. There we go. So the only thing I'm missing right now is I'm not seeing where we, so we ask for the ID here. When we pass the complete action here, do I need to
Ricky: You don't need the ID there, because you can just instead of passing it to complete action, you can just delete that and do to do ID. There.
Jason: Oh, right. Okay. Yeah, that makes sense. Because we have, we're basically encapsulating that.
Ricky: Let's see if it works.
Jason: Okay. Cool. It did something. We're getting a delay.
Ricky: Oh, can you look in the to do item, async input.
Jason: Uh huh.
Ricky: Set Optimistic() value not event dot target dot value, because you're toggling it. There you go.
Jason: What am I doing. It is fast once. And then is not fast the second time.
Ricky: Hmm.
Jason: Optimistic() value.
Ricky: So instead of this target value, do not Optimistic() value. Sorry. There you go.
Jason: There we go.
Ricky: Sorry about that.
Jason: No all good. This is great. This feels good. We don't have to do with that untyped event.
Ricky: Now you can use the async input anywhere. You'll automatically get an Optimistic() update. No matter what you do that's either async or sync or navigatings or anything, you will always get that Optimistic() value immediate. If you're thinking about this, if you had a design component library that already supported action props and had the data fetching library that already did the transitions in the refresh to dos. As the product developer, you look at the to do item component, all you really have to do is write the code that like what do I do when I complete the post to that ID. And write, the loading states and Optimistic() updates you don't write. It is handled for you.
Jason: Yeah. I think this is, this is great. Right? Like this is I think this is really it like I said before, it just cleans up my mental model and makes me feel better doing these types of things inside of React. Before I felt like I was working against ingrain, now I'm doing the things my brain wants to do. I'm making calls to load data in line. When I want to change something, I change something. You know, I'm not like figuring out how to trigger the dirty checks or reset my effect or any of these things. I'm off of the loop d loops of the effect style hooks and into something that feels linear, the way that I would think about these processes. Click, do a thing, do the next thing, and continue with your business. And letting React handle all of those rendering checks. Like I don't have to know that React renders components every time something changes. That is a really big mental burden to liftoff your shoulders. Not having to care when React is going to rerender, you optimized that way inside of the calls.
Ricky: Yeah, the other interesting aspect here, you are kind of writing this thinking about it more being synchronous, so you look at the get to dos and stuff, all of this other stuff, as you're kind of like offloading the mental burden of needing to handle all of the different pacing stuff.
Jason: Right. Yeah. I'm on it. I'm a big fan of it. This is a a huge improvement. And I am I'm excited to like implement this into the React code that I write. We are over time. So Ricky, thank you so much. If people want to get deeper into this, where should we send them? Like I'm going to send people to, again, the React talk that you did where you go over these APIs. And send them to the use docs.
Ricky: Yeah, so one of the things I announced at, during my talk, at React conference. The next step for this is to get the patterns implemented across libraries to make it really easy to use. So, just using React query, or a routing library or design library, you get the features by default. So we created a new working group on GitHub and invited a bunch of experts from the community to help understand and help educate on these, GitHub.com class react working group. /asyncreact. Here it is.
Jason: Get in here, look at discussions. I can link directly to discussions. That makes more sense. So Ricky, thank you so much. I will send people one more time to your Bluesky as well as your Twitter. We are going to be back with more "Learn with Jason" in the coming weeks. I'm working on scheduling now. Ricky, any parting words for everybody before we sign off here?
Ricky: No, this is dope. React is good, actually.
Jason: React is good actually. Yeah. Very much feeling that after seeing the new APIs. So thank you, Ricky are being here. Thank you for watching. If you're enjoying the show, like, subscribe and do all of the other things. Thank you for watching "Learn with Jason." We'll see you next time.