Async React provides primitives like Suspense, transitions, and optimistic updates to manage the three critical in-between states (busy, loading, and done) that occur during async operations, transforming non-responsive applications into smooth, interactive experiences by coordinating async work within the React render cycle.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
Designing the In-Between States with Async React - Aurora ScharffAdded:
All right, let's get started. Um, I am so excited to be here and kick this conference off. So, my name is Zoros Sharf. I work with developer experience um with on the Nexus team, Absel. And we're going to see how to design the in-between states with Async React today. I know that agents are everywhere, but we're going to do some old-fashioned coding today, okay? But uh stay uh stay until the end because I do have something for your agents uh coming. So, let's get started. So, uh to learn about Async React, I built an app, of course. This is event hub. It's like a conference companion app. You can see my session here and other sessions. And then you can like filter and uh favorite and interact with sessions with comments and questions and such. But right now, this app is super broken. Let me show you what's the problem with it. So, um, if I click around, you'll see there's like lots of delays here.
It's very non-responsive. You'll see it takes a while to filter and even the session page is super broken. I have like the worst layout shift ever. Um, and the questions are also slow and everything just feels super not uh interactive, right? So, why does it do this? Well, the problem is not really that the app is that slow. It's more that we um didn't design the moment between the user action and the actual result, right? So, it feels very slow even though it's not that slow. So, what's missing here is the in between states. And this is more of a UX problem than a DX problem. So, typically we as developers might not think about this as much or do it in the wrong way. Um to better understand why what's happening here, let's look at the react render cycle.
So yeah, this should be familiar. Uh in React, we have an event for example user click which would trigger an update where react would figure out what has changed which then schedules a rerender where components are rendered and then finally uh a commit is made to update the DOM. Totally fine when everything is asynchronous. Now bring async into this and um you'll have all of a sudden these states that are unmanaged. So between event update there might be a busy state where the server is still responding.
Between update and render there might be a loading state where we're loading some data. And between render and commit there might be a state where the content is ready but it hasn't yet been replaced into the UI. Yeah. So this is what we're going to work on. And you can handle this with like use effect, use state, add a bunch of that, lots of boiler plate and uh potential race conditions.
Uh wouldn't recommend. The problem with that is it's outside of the react cycle.
So it's hard to get it to be um a smooth uh transition.
So to solve this problem, the react team introduced something called async react, which is like a set of primitives to coordinate a synchronous work for you automatically. Uh and the key here is transitions. So a transition would wrap the entire React render cycle here and uh wrap it all as an action which can then commit once all of the interactions are ready within this render cycle so that you don't get any weird flickers or intermediate states or bugs.
And for each of these um uh steps you can use one of the um features of async react. Uh for the busy state you can bridge the gap here on the um by adding some sort of feedback or yeah optimistic updates. For the loading you can use suspense and provide fallbacks. And then for the done you can even add a view transition to animate the transition between the loading into the content or whatever it is you're doing.
So these um gaps are really crucial to manage when the network is slow. But um what's really cool is that when the network is fast, they essentially disappear and the whole interaction would still feel synchronous. So that's like the goal here, right?
And we encounter these problems whenever we do async data loading or async navigation or async mutations.
And um async react really shines when you're using some sort of framework that is integrated with it. So for example, I'm going to be using next.js app router where the router uses transitions and my data fetching with server components is going to work with suspense.
So let's go ahead and use this to fix our app.
So here in the code, I'm going to check if this is big enough for you guys. Um let's first fix the async data loading problem. You might see I have an error here and I also have sort of a performance problem right now. So there's like a one second delay before my app is actually able to load and the issue is also telling me this. So I'm using cache components in the Nexus app router and with that I'm getting help that I likely have some sort of performance problem here which is that my get user favorites is blocking my whole page from loading and I'm also getting some help on how to fix it. We can cache the data. We can move it within suspense or we can allow this route to be blocking which I don't want to do. I'm going to go for a suspense.
So suspense can let me declaratively define a fallback for a specific component. And checking out what's here.
Uh this is the event grid that's triggering this error. So that means I need to wrap this with suspense so that I can stream in this component and unblock the UI. Let's go ahead and do that. Over here I'll have my event grid.
So, I know that this is the blocking component. I'm going to add a suspense.
Who loves suspense?
Where's suspense? Okay, sounds like talking about suspense. I love suspense.
Okay, let's do a fallback here so that we can unblock this UI.
And um we're going to do just a nice skeleton that is like matching my content. Let's add this here. And we can wrap this around um the event grid here.
And um yeah so I can just define my loading state declaratively and stream in this component. Notice when I reload now I have unblocked the page I have this static shell instantly available while the dynamic content streams in.
So this is making the app already feel fast and predictable.
Um and the best part is that with server components we get this optimal performance while still being able to fetch data locally as we love to do in React.
All right. Um, so that's the learning state, but with async react, we can also very easily add animations to the done state. So I'm going to do that with view transitions.
So, uh, they're pretty simple. They would trigger in transitions and suspense. And I'm using suspense. So I can wrap a view transition around this.
And it's a pretty like subtle cross fade right now. You might not even see it.
Um, let's add some custom CSS to make this more visible. I'm going to animate the enter um activator for V transition and do a slide uh up for this one. This is my favorite view transition pattern by the way. And for the fallback, we can animate that too and do a slide down.
And let's wrap this around here. And let's see if that looks any better.
Beautiful. Right. Okay. So, that's our first in between state designed already.
It's Woo. Okay. clap for that.
It's a very simple one. We're going to make a lot more. Um, okay.
Let's use the same pattern now for the next loading state we have, which is on this uh session page. It's terrible, right? Like what is that? Um, let's fix that one. So, it is using suspense. It's not blocking, but it's doesn't have a fallback. And then the comment list is just like a generic spinner. So um all we need to do is just add a appropriate loading state for this so that it will feel more predictable. Let's add a fallback. We're going to do uh one that I already created that's the right size.
And for the comment list, let's do the same thing. Let's do a nicely sized skeleton.
And uh yeah, that should be able to fix our problem here.
Now that's all right, but sometimes the best in between state could be none at all. And in nextJS, we can eliminate certain states by caching parts of the the UI. So I want to cache this part here because this is just shared across all users. I don't need to load this every time. So we can actually add a uh I love I know you guys love directives.
We're going to add use cache which will uh allow me to reuse the return value of this function across users.
And it's still triggering my suspense right now. And that's because I have this personalized heart right here, which is for me as a user. So that's preventing me from caching this because this is personalized, right? So to fix that, let's just um move out the personalized piece of this and stream it in. So I'm going to just pass it as a prop. This is like if you've done like donut pattern sort of things with server components, it's kind of like that but for caching.
And this should allow me to now instantly see this part of the UI. So I don't even need a loading state here.
And to add back the suspense uh sorry the favorite. Let's put it here. Let's wrap it in a very small cute icon uh fallback like this.
And like that.
Let's see. Beautiful. There we go. So I'm still keeping my personalized content here. Um yeah. So I think that's Oh yeah, we have one more problem here which is this questions which is also blocking and reloading. I can find out why it's blocking. I'm going to get some help from Next.js. It's over here in the question queries and it is my question feed component. So we already know how to handle this. We're going to do the exact same thing in the questions page.
And um sorry, I'm like scroll down. This is the blocking component. We are going to do a uh suspense with some animations for this one as well. And that's it.
Amazing.
Yeah. So now it's instant. It has the static part and then streaming in the rest. Okay, that's async data loading designed. Let's move on to the next step.
So uh the next thing we want to work in work on is async navigation.
Right now I have a couple of places where I'm doing a navigation which sorry uh which is over here in these tabs. So it's conceptually on the same page but it is a navigation because I'm using search params as you might be able to see in the top here. So that one and these um filters are using search params re fetching data and it's it's not responsive right. How can we fix this?
Let me check uh my home tabs which is the bottom part of this this UI. And I have this sort of design component which is my Miami React Miami themed um navigation here at the bottom. What if this component could handle the async coordination for me? Let's go ahead and change this to this magical property called action uh and see how it's going to change the UI.
Do you see that? Let me move this. So just by doing that, I now have this instant uh navigation or instant uh responsive click here in in the tabs and a fade as the data is loading in the background. So what is this action?
It's not really that um magical. It's just a property with the name action that is called inside inside a transition. So here this design component is coordinating the async work automatically uh by itself letting us as the consumer just do whatever we want do any sort of asynchronous things and it's going to be automatically handling that.
So this is called the action props pattern and um it's it's pretty nice. It means I can just um pass that and it's going to work.
Let's also use uh see if we can use the same pattern on on the tabs up here or the filters.
So I mean you might have guessed it but there is an action prop here.
And um to use the correct naming convention, I'm going to also change this to change action which which is whenever we call something inside transition, we should call it action so that it's clear what sort of behavior this is. And let's see if that will also work.
There we go. Amazing. And notice how I can like interrupt my navigations here.
So it's um yeah, it's using transitions.
We can interrupt them. We can change our mind without waiting for all the content to load first.
So here's the thing with this. Um the idea is that UI components like my toggle group like my bottomnav can adopt the uh action pattern or even component libraries like base UI or radics can do this so that we again as a consumer or user of these libraries don't have to worry about any of this asynchronous coordination and just get the benefits right away. So hopefully we will see that happen so that all of our autocompletes and drop downs all do this automatically.
So that's it for async navigation. We now have this instant uh feedback instead of frozen and janky states.
Let's do a couple more fun things.
So um I want to actually add few more animations to my navigation. So when I click between this year the session and go back I would like some sort of slide like you know you commonly see on mobile apps I'm sliding back and forth. So we're going to add that too.
To do that, I'm going to need to wrap my session page over here in a nav forward.
So, I'm going to show you what this is in a second. Let me just wrap this all over this page.
Um, this is, of course, is a view transition. I just extracted it out here with some custom CSS to define my sliding back and forth behavior.
We're also going to use the nav back for the homepage to get it to animate back.
So, let's do that, too. That's over here.
nav back. And yeah, you already know what this is.
Sorry. Sometimes it's hard to code, huh?
Um, and to be able to trigger this view transition appropriately when we click this card, we're going to use um a different feature in transitions. So, let me find the card and it's inside here. I have this event card and we can add a specific type of transition type to decide what animation is going to be triggered on this link.
So, let's do transition types. This is really just a Nex.js shortcut for add transition type which is a React feature. So, we can do nav forward.
There we go. And that should be enough to give me a beautiful slide. Sweet.
Let's also do the back. We're already like doing great here. So I'm keeping this back button inside a set of session tabs which is using the same reusable component. We're going to change this to an action. So we can use retransitions.
And we're going back to the homepage. We can use the manual programmatic version.
Add transition type n back.
Let's see if it's going to work.
There we go. Feels like an app now, huh?
Pretty cool.
Okay, so yeah, let's move on to our final um like problem area, which is the async mutation. So you saw this heart is like not responsive at all. And I have a bunch of other problems, too. Let's just deal with this this one first.
So since these are like mutations that are unlikely to fail, we can go ahead and eliminate them entirely as we did with uh the caching earlier, we can now eliminate these uh in between states with optimistic updates. Uh and they can automatically just roll back if there's some sort of error. We don't have to worry about that. So let's head over to this favorite button and and do this.
And I don't have any action props here.
I have to do it myself. Uh that's all right. It's it's not that hard. Let's do um use optimistic here. So let's call this and we're going to pass in our like real value here, the one that's updating after a second or so as an argument and it will return a value which can be optimistic and then a setter function. So let me just use this all over this component and um optimistic updates are meant to be coordinated with async react. Do I need some sort of transition or action prop? And forms have that built in. So, we can just switch this to a form for fun. Let's do a form here.
If I can type it. Um, like that.
And then close it up. And in here, we're going to move our mutation. And we're going to coordinate our optimistic update too inside this. and get rid of the rent default.
And that should be enough to handle my optimistic update here. Let's try it out. So, it works. And what's really nice is that, you know, you can click this and then you can click again. And as you navigate around, since we're using as React for everything, it's just one smooth transition from the tabs to the result of these mutations with no like weird flickers or intermediate states.
All right. Um, we're going to do a few more optimistic bits here. So, let's work on the questions. We didn't actually see them that much yet.
They're over here. I have this question page. Let me just filter by newest and find out where my form is. That would be here in the questions page. Uh, we saw this question feed. It has a form which is very slow right now and unresponsive.
There we go. So yeah, we're going to fix this. And I'm going to switch this out for a pretty cool component, optimistic questions. I just learned this pattern, by the way. Um, but essentially what we do is we have this fake set of questions that just exists temporarily and then the real questions are still on the server side. So I just fall back to an empty list when there's nothing to do.
So that means that we can um fire off some questions and they will be sending and then they can just resolve later as the server updates.
Pretty nice. Um yeah, what about the upvote? This one is also slow right now.
We can fix this one. See, it takes quite a while here. Uh let's add a bunch of cool features to this this feature.
So we're gonna work on that foot first.
You might have guessed what I'm going to do. I'm going to add some logic here. And I'm going to use the updater um I don't know reducer function of use optimistic to handle this increment and like make sure they can only upload once. Let's use optimistic votes as our values in the app.
Did I add it everywhere?
Here.
Yeah, that should be fine.
And then we just need to add an upote inside this form action.
Coordinate it with everything else.
Oh, I did something really weird, didn't I? Do you see that?
Okay. Okay. Let me fix this. I can do this.
Okay, there it is. Oh, thank God.
Okay, manual coding. We're going to get through it. Cool. Great.
Thank you for that. That was almost went terribly bad. Okay. Um and I also lost my up vote. Wait.
I mean, this is a demo, right? We have to have some pro problems. Up vote. Put it back here.
We should be good now.
Sorry about that. All right. We're going to see this in action in a bit. But before we do that, let me add some more features because when we reorder, we it's hard to see where the resulting um question is going. So, we're going to animate that, too. Let's very simply add a view transition around our question card.
All we need is a view transition that can have a key and React will be able to handle the rest.
Let's see if I can get this working.
like this. Remove the key from here. So now React can animate this uh as we u upload. And one more thing I want to add. I want to add a falling feature. So right now we're handling the mutation, but what if there's like an update from a different user or you know some sort of background update? In this polar I'm just doing a router refresh on an interval. And since we're using the next router which uses transitions, this should be able to also animate whatever is happening. Let's try all of this out in a sec.
Um I hope it's going to work. All right.
So I have my two different um users here. It's just me, but you'll see the result.
So let's try. Let's do one.
And it should as it settles appear on the other side. Beautiful. Let's do.
And it should also animate. Nice.
I mean, it's good, right? Hi.
And guess what? If we upvote, it should also animate our resulting other user.
Yeah, I I love this feature. It's such such simple code. Uh yeah, so that's our async mutations also designed and our app can handle both uh directions with mutation and then background update with this responsive and alive feeling application.
Okay, let's review what we've done here.
Um I mean we have to get rid of this, right? If we're going to remember how bad it was. Let me just get rid of this.
Sorry about that. Um and let's see what it looked like before.
Oh my gosh.
It's It feels awful, right? Yeah. What is this? Yeah. So, this is what we had before. We had like very frozen uh interactions and jumping layouts and no feedback on our different clicks, very harsh transitions. Let's did deploy this, of course, uh so we can just get the nice version again. Yeah, we have our animations and uh the the caching, the optimistic updates here. Questions are loading in. Everything is just amazing.
So, um remember the the app is not actually any faster. It's still the same delays, but since we designed the in between states intentionally like this, it just feels like a completely different experience.
Um yeah, and by doing all of this, we did increase the first contentful paint, the interaction next paint, uh and cumulative layout shift. So we're improving the core web vital as well which will give us better performance and SEO and uh this is a pretty small app but the patterns scale. So with server components streaming in data or um and caching them with cache components we will guarantee this fast load and use async react to coordinate everything to make it responsive and we will get apps that are resilient and interactive by default. So your users are going to thank you for this. I did say agents at the beginning. Uh let's go back to that.
If you're interested in using your transitions but you don't want to learn them that much. I have a skill that I created. So it's here. Uh React view transitions. I've been using this. It's working really well. If you want to try it on your app, go ahead. You can get it um at the end of this talk. So yeah, it will be here. Thank you guys.
Related Videos
Agentforce NOW AMA: Build with React and Salesforce Multi-Framework
SalesforceDevs
490 views•2026-05-28
How agent o11y differs from traditional o11y — Phil Hetzel, Braintrust
aiDotEngineer
450 views•2026-05-28
WEB TECHNOLOGIES UNIT-2 | Degree 4th sem BCOM Computers web technologies unit-2 full explanation💯✅
LearnwithSahera
1K views•2026-05-29
More tests are always better? How to use AI to identify tests that bring little value
Alliance4Qualification
335 views•2026-05-29
Search Algorithms Explained in 60 Seconds! 🤖💨
samarthtuliofficial
218 views•2026-06-01
People of Game of Thrones using JavaScript DOM
AltCampus
296 views•2026-05-30
Introduction to Problem Solving Part - 1 | Lecture 1 | Intermediate DSA
ascensionix
107 views•2026-05-29
🚀 BCS613C Compiler Design | Module 1 to 5 Schema Evaluation 🔥 | VTU 6th Sem 💯 #VTU #bcs613c #exam
Pranavaa-y4y
104 views•2026-06-02











