What's New in React 19 (and What That Means for You), with Dev Agrawal
Dev Agrawal (00:00):
If we don't use any of these new fancy hooks, as long as we just keep using Suspense and formActions like React wants us to, we will always have consistent and bug-free UI. We won't have inconsistent glitches. We won't have tearing. We won't have, okay, one piece of state here shows something, but here you have something else.
(00:21):
We won't have things like race conditions. So, all of those things have been eliminated in the fundamental model that we are using.
Alex Booker (00:26):
That was Dev Agrawal, software engineer at Smartdata. If Dev sounds familiar, maybe you caught our interview earlier in the year about the State of React in 2024 and If You Should Still Learn It. Of course, you should still learn React. And in fact, you should learn React 19, which is the subject of today's interview.
(00:49):
React 19 is the latest version of React and it introduces some amazing features like the React Compiler, Actions, Server Components, and a bunch of other treats that improve the developer experience. Dev is truly a beacon of knowledge when it comes to the latest and greatest in React.
(01:05):
Beacon teaches not only about the new features, but some of the context and history surrounding their conception so that we can best understand them, the problems they solve, and make the most of them in our applications. I'm your host Alex Booker and you're listening to The Scrimba Podcast. Let's get into it. So, first of all, React 19, is it out in the production version? Can we use it today in our applications?
Dev Agrawal (01:30):
Not yet. React 19 is currently out as an RC, release candidate, which means this is the version of React 19 that they're pretty sure that they're going to release. But before they officially make it a stable production ready to release, we can go in and provide feedback on everything that they have so far.
Alex Booker (01:50):
Yeah. React are pretty good, aren't they, moving slowly, I would say in the sense that there aren't breaking changes. And before it goes into a major version, they release that RC to be absolutely confident everything is working well. And they're going to commit to the API as it is in that RC version?
Dev Agrawal (02:07):
Yeah, for a project that size, that's basically the only way you can do release something new, because we have seen what happened with Angular.
Alex Booker (02:14):
I know last time we spoke we got to speak about things like Server Actions and how they were a feature of not a React version, but React Canary, the only meta-frameworks would implement for us. Is React Canary and RC the same thing? I guess they share an acronym.
Dev Agrawal (02:29):
So, I think everything... All their experiments that were under the Canary release, they're finally coming as a production release in React 19. So, all those experimental things that they're working on, React 19 is going to be like, "Okay, now we are finally done with all of it. Here's the latest React version that implements it."
Alex Booker (02:48):
So, it's just a coincidence that React Canary is RC and release candidate is RC as well. That's just a total coincidence?
Dev Agrawal (02:55):
Pretty much.
Alex Booker (02:56):
That's wild. I want to say they did that on purpose, but then Canary is because it's like a canary in a coal mine type of thing. That's a pretty lucky coincidence. So, when can we expect React 19 to come out, or is it a bit early to say?
Dev Agrawal (03:09):
I'm not fully sure about that. The React 19 RC announcement was about a month ago. You can probably follow their discussions on GitHub or wherever they have these discussions to figure out if they have any plans on, "Okay, this is the date we are going to make this live." But so far, I don't have specific knowledge of, "Okay, this is the date that we are going to have React 19 stable."
Alex Booker (03:30):
What were some of the standout features of React 19 that we should know about? How would you describe the release in general? What should people know?
Dev Agrawal (03:38):
Last time I was on this podcast, we talked a little bit about how React hasn't shipped a new version or any new features in many years. I think React 19 is basically that, "Here are things that we have been working on for many, many years that have been very difficult to work on. We're finally done with them. Here. Here's everything you asked for."
Alex Booker (03:58):
They must have heard you on the podcast, Dev. They were like, "Oh, crap, we've got to release something big."
Dev Agrawal (04:02):
Yeah, I'm sure they heard me on the podcast and a lot of other people who have been very loudly screaming about React not having anything new for many years.
Alex Booker (04:11):
When it comes to new versions of things, there's often a flagship feature or two and then other features. What are the flagship features we could say of React 19?
Dev Agrawal (04:22):
I think the biggest flagship of React 19 was definitely the compiler because it's something that they have kind of put a huge bet on for many years. Every time there's any discussions around performance or the DX kind of edge cases or dependency arrays, anything weird or something that takes a long time or something that is a big issue for most developers, the compiler was always brought up as compiler's going to fix this issue.
(04:50):
Compiler's going to fix all those issues. And now that we finally have it, I think that's certainly the biggest flagship thing that React has worked on that they are also very excited about.
Alex Booker (05:02):
So, it's early days for those high expectations for the React Compiler is what you're saying?
Dev Agrawal (05:06):
Mm-hmm. And it looks like the compiler was already in production used before they released it.
Alex Booker (05:06):
Oh, cool.
Dev Agrawal (05:12):
So, it looks like there's also a lot of real case studies that show that, okay, the compiler has been very helpful.
Alex Booker (05:17):
I've been seeing videos in my YouTube feed like, "This new React 19 feature will make your app 20% faster." And I've seen posts about the React Compiler and how it relates to performance. Before we can understand that, I think we have to take a moment to understand useCallback and useMemo, which are two performance related React hooks that the compiler simplifies for us.
(05:39):
They simplify the developer experience going forward. So, before we mention React Compiler again, I was wondering if you could set the stage by talking a little bit about the problem that useCallback and useMemo solve and what that looks like today.
Dev Agrawal (05:53):
I'll start this by saying the thing about React that has always been the most appealing was its focus on simplicity, its focus on removing all the extra things that we used to do to make our applications work, and just give us a model where we have a component that takes some data and returns some UI. And React is going to read on it every time some data changes so that it knows it always has the latest and the most consistent UI that it can show to the user.
(06:21):
Unfortunately, while this model is really simple and really nice to work with, and it's one of the big reasons why React has exploded in popularity, it was always a little inefficient because React re-renders the components all the time. Every time there is potentially any state, any input that might have changed, this results in a lot of unnecessary extra work being done.
(06:42):
So, if you have a component that has 10 inputs and only one of those inputs changed, React will still rerun the entire component. And the way that React asks us to opt out of it, or to tell React, "Hey, here are some things that don't need to rerun as often. Here are some things that you can apply the brakes to. Here are five inputs that this very expensive computation depends on, so that React doesn't need to rerun that all the time."
(07:10):
It can rerun everything else, but that expensive piece of computation can stay memoized. Or we remember what the value was the last time, we're just going to use that. So, that was the idea behind the useMemo and the useCallback hooks or the React.memo which you can use to memoize the entire component outputs.
Alex Booker (07:30):
That's a brilliant explanation. I really appreciate that. I remember with React, sometimes I will console log something and then I go to the log and it's running a lot more than I thought it would. And at first, I thought, "Oh, no, I'm doing something really wrong." But as I learned more about React, I realized that rendering can be very cheap and sometimes that's just the consequence of the way React works, the way the if states updates, the UI gets re-render.
(07:55):
Then, every now and again, it does become a problem because you're doing something computationally expensive or something that you really don't want to happen twice. That's where useCallback and useMemo come in. I always wondered though, sometimes I was tempted to use useMemo or useCallback in places where there's a cost associated with them.
(08:13):
Not a performance cost, but it makes your code a bit less clean, I think. When do you typically decide to use things like useCallback and useMemo?
Dev Agrawal (08:21):
Yeah, I love that you bring this up because there actually is a small performance cost associated with memoizing.
Alex Booker (08:21):
Oh, seriously?
Dev Agrawal (08:28):
Yeah. So, I'll quickly go back to the idea that because React re-render so often, it's inherently a very inefficient system. So, memoizing is not the only way to produce performance. Dan Abramov has an amazing blog post called Before You Memo, which talks about some composition tricks of pulling state as down into your tree as you can and lifting most of your content outside of your stateful components.
(08:56):
But obviously, you cannot always do that. This is not something you would naturally do with a component. And the same applies with memoization. First thing is that the performance cost of memoization is that you need to give it a dependency array, which means every time the component re-renders, React is going to iterate through or check that entire dependency array with the dependencies from the last re-render.
(09:17):
And it's going to check if any of them changed. And if they didn't change, it's going to reuse the previous value. So, there is some memory and computation cost associated with memoizing, which is why memoizing everything is never a good advice. Because if you over-memoize, you're probably going to cause more performance issues than you were solving because maybe a computation isn't really heavy expensive.
(09:42):
And there's always the trade-off between should you memoize or not. So, the tricky thing always there is that you should find the expensive things. For example, if you have an array with 100 items and you're doing a dot map or a dot filter through it, you should make sure that you only do that when that array actually changes. You shouldn't do that when some other piece of state changed. And here, you have the exact same value.
(10:05):
So, recognizing some of those expensive computations and then trying to memoize them. So, that was always one of the tricky parts. The other tricky part was that dependency arrays. Every time you optimize some part of your code to be nicely memoized and not rerun too often. Let's imagine now you have this component and you make a change or do the requirements change or you have to add new features.
(10:28):
It's very easy for any new feature that gets added to a component to just break all the memoization. Memoization is basically very brittle. Because we need to make sure that whatever we are memoizing we know exactly what the inputs are and we know that they're not going to change that often. We have to choose those dependencies very smartly.
(10:46):
And every time we add new dependencies, we now have to rethink the entire thing. So, memoization is, first of all, it's tricky to do. It has a trade-off. It's not just memoize and you'll be fine. And it's very brittle. These are some of the problems that have existed-
Alex Booker (11:02):
Has existed.
Dev Agrawal (11:03):
... with memoization.
Alex Booker (11:04):
Please, Dev, tell me there's a solution to all of these challenges.
Dev Agrawal (11:08):
The compiler.
Alex Booker (11:11):
How does the React Compiler help?
Dev Agrawal (11:13):
So, the fundamental idea of the compiler is actually very similar to the fine-grained reactivity model that you will see in pretty much every other framework today. SolidJS has obviously pioneered it, but you have Vue, Svelte, Preact, everyone trying to switch to using this fine-grained model. And the idea is that every time you write some code, every time you have some computation or some side effect or some rendering, it has certain dependencies.
(11:40):
So, if I render a list of to-dos, the dependency there is an array of to-do list that I probably get from a server somewhere or that's stored in a piece of state somewhere. The compiler basically has a very in-depth understanding of the JavaScript language. So, it's doing similar things that would happen inside the V8 engine or any runtime that deeply understands your JavaScript code.
(12:03):
But what this compiler does is it is able to figure out what dependencies, what are the inputs, what are the state objects that every part of your code depends on, and it wraps them inside simple if statements that check, has this value changed from the last time or have these three values changed from the last re-render? If they have not, it'll just spit the output that was given the last re-render.
(12:29):
And if any of them have changed, it's going to run that specific piece of code. And again, it's going to store the output so that it can be reused later. It basically automatically memoizes, but it does it at a much smaller level, much more fine-grained level than you would probably do with useMemo.
(12:46):
And the way it memoizes is a bit more efficient than useCallback because you don't have dependency arrays that you're traversing through and checking at each point. It just uses simple if statements.
Alex Booker (12:59):
So, could you theoretically accomplish what the compiler does if you manually updated your code to make it more fine-grained? And you were willing to deal with all those tricky parts you described and be very, very considered about all of the possible inputs. Or does the compiler bring something apart from the fact that it makes it easier?
Dev Agrawal (13:22):
So, there is a React Playground. If you go to Playground.React.dev, it's basically a playground for the compiler. And what you can do is you can write your normal React code on one side and you can see the generated output on the other side.
Alex Booker (13:37):
That's so cool.
Dev Agrawal (13:38):
It doesn't look too complicated. It does look like something that you could do by hand if you use a special cache hook that we don't really have access to. But other than that, it looks like something you could do with hand because it's just using a bunch of if statements. But obviously it's not something that you could do in any real production application, and that was the whole point.
Alex Booker (13:59):
It's crazy, right? Because I bet if you look at the output of the compiler, even though you could have done it by hand potentially and you can reason about it, it probably is quite a bit longer. It's probably quite a lot less clean. You'd be very considered about doing that in your own code base. Whereas the compiler applies a degree of, I like to call it syntactic sugar, where you express it very succinctly.
(14:23):
The compiler builds all this intelligence about not just the tokens and the structure of the code, but the meaning and the semantics. And it can use that to then output something that is optimized and allows you to keep your code very clean, and probably maybe it's fair to say make your code faster by default. Is that a reasonable thing to say, do you think?
Dev Agrawal (14:42):
Correct. Yeah. So, the primary selling point of the compiler is not that it just magically improves the performance of your code. The much bigger implication here is that we no longer have to think about performance. Think about all the content, all the articles, all the videos that exist out there on how to make your React a performant.
(15:01):
That's an entire category of DX issues or things that we as React developers have to think about when we are writing our code. That just got eliminated. That's the main point of the compiler is that whatever way you write your React code, it's going to end up in the most optimized version. Now that that's not an impossible task, you could write very performant React code by hand if you wanted to.
(15:25):
It's just that there's a huge gap between writing normal idiomatic React code or simple React code and writing performant React code. This is a gap that we always had to traverse manually and it required a lot of effort. And the compiler just eliminates that gap.
Alex Booker (15:41):
How do you use the React Compiler? What does it look like in practical terms?
Dev Agrawal (15:45):
Currently, there are a couple different ways to use it. There is a Babel plugin that you can hook into your Babel workflow and it'll make sure that your components go through the compiler step. I think Next.js and Remix and these frameworks are adding support for it. So, if you're using any of these frameworks, soon, you'll be able to use the compiler as well.
(16:04):
But mostly, the compiler is designed to work behind the scenes. It's not something that you should have to think about. If the compiler goes through your code and it can optimize, it will. But if there's any components any place where you're breaking React's rules, if you're breaking how React works fundamentally for any reason, it's just going to not compile that part of your code.
(16:26):
Or even better, soon, it'll be able to tell you exactly, "Hey, here's this component that we were not able to compile. But if you fix these two small issues, we will be able to compile it and make it a lot more efficient." Yeah, it's designed very much to be an assisting tool, be something that works in the background and helps you write better code, and then optimize your code for production.
Alex Booker (16:48):
That reminds me of something else I've read about React 19 and the compiler, which is that you have to abide by the React rules for it to do its job well. And maybe what you were describing is some of the feedback you get from the compiler if you haven't followed the rules well enough to benefit from the compiler.
Dev Agrawal (17:04):
Yeah, I see it as... React has always said that it's just a library, but at this point, we all know that it's not. It's a lot more than just library. But what the compiler really nails home is that it's actually a language. React is very much a specific language that's a superset of JavaScript in some senses, which is this is the language that we use to declare how our UI should work or how our UI should look like.
(17:31):
The rules of hooks or the rules of React very much bring that to light. These are the rules that you have to follow when you're writing React code or when you're writing code that's going to be consumed by React.
Alex Booker (17:44):
Wow.
Dev Agrawal (17:44):
And once you follow all those rules, that's also what enables the compiler in the first place is that React is such a strict and well-defined language for UIs that they can build a compiler on top of it that fully understands not only the rules of JavaScript, but also the rules of React. And it's able to compile code as long as you follow those rules. It can optimize it as much as it can.
Alex Booker (18:10):
You're blowing my mind a little bit, to be honest, because I never thought about React in those terms. But the acknowledgement of rules in React, and then you have things like JSX as well, you could see how that could be a language because a language has rules. It's just like in JavaScript how you have to use specific syntax, or you can't use certain keywords, or you can't do things with different data types if they don't match.
(18:31):
With React, you're not meant to have side effects in some situations and other rules like this. Wow. I never thought about it in those terms because I always thought of React as the, I haven't called it a library for a long time. I've always seen it as a progressive framework where you get the UI rendering part and then you bring in your own extra bits like React Router or whatever, React Query.
(18:52):
And then, in terms of the language, I've always thought it is just JavaScript ES6 or whatever, plus JSX. Is there more than just JSX as far as the syntax is concerned with React or is it really just that?
Dev Agrawal (19:03):
As far as the syntax is concerned, I don't think so. I think the only other kind of syntax that probably is mostly just convention is that your components should start with upper case letters and your hooks should start with a "use" keyword. I'm not fully sure if these are things that the compiler itself looks at to figure out what is a component and what is a hook. It probably does.
(19:25):
But there's no other syntactical additions that React makes. And JSX itself, it's not like... React started JSX, but a lot of other frameworks have adopted JSX as well, and that's just syntactic sugar for us to have an easier time defining our markup in JavaScript. With React, it's all semantics.
Alex Booker (19:44):
It's really interesting, we're landing on this subject because something that confuses me a little bit honestly is the difference between a transpiler and a compiler. Because ever since the beginning of React really, we've relied on things like Babel and Babel plugins to take that JSX syntax, which the V8 engine does not recognize. It only recognizes JavaScript according to the whatever, ECMA, Spack.
(20:09):
And JSX isn't part of that. So, if a transpiler looks at your JavaScript code or your JSX code specifically, analyzes it and then converts it to another JavaScript file where it calls functions at runtime like React.createElements and it converts all these props into objects essentially, and you could, if you wanted to, express your React components that way. It's just not as expressive as using JSX.
(20:32):
So now, I hear about the React Compiler and it's a very similar step, isn't it? You're taking a React JavaScript file, JSX file, and then you're converting it into another JS file, but this time it's added or augmented the code so that you don't have to use those hooks like useCallback anymore. It makes me wonder how they relate to each other. And I also think, "Well, could the compiler technically do that JSX conversion as well at the same time?"
Dev Agrawal (20:58):
I don't know. The compiler versus transpiler debate is, I used to be invested in it, but at some point, I realized that it's all a compiler. It's just that a compiler tends to be a spectrum of how much work is the compiler doing. Is it just transforming one syntax into another or is it fully rewriting your code? Or is it compiling into a different programming language, a lowered level language so that it can be executed efficiently?
(21:22):
I think I've started to see all of it as this, it's all just compilers. What exactly is the compiler doing? It's all in a spectrum instead of these are explicitly different categories of compilers, transpilers or things like that. But yeah, I think those are our separate responsibilities, turning JSX into dot createElement and turning normal React code into a bunch of if statements that automatically memoize things.
Alex Booker (21:48):
I'm quite forgiving about what transpiler/compiler taxonomy. I don't mind that much. But I guess what I was curious about is how these pieces fit together. And what you're saying is that they are kind of modular and separated by design. Maybe you'll help me fill in the blanks here because I always use Babel and a Babel JSX plugin, but I'm sure there are other packages that could accomplish the same thing.
(22:11):
So, it's kind of true to React, isn't it, how you can pick and choose. React Compiler, with React, that's always going to make sense, but when it comes to the other parts, there isn't elements of modularity there. So, you're not locked into one big monolithic tool. You get to pick and choose.
(22:25):
And apart from flexibility, maybe that helps the developer landscape move a bit more smoothly because now people can innovate and you can adapt things incrementally and stuff like that. It sounds like it's all about the modularity of it and not the taxonomy.
Dev Agrawal (22:38):
Yeah, and Babel has gone through many changes because obviously the language, the platforms, everything evolve. So, the tooling has to evolve with it. And I don't think Babel is used much at this point. The Babel plugin for the React Compiler, that's just one way to hook it into your workflow.
(22:54):
Most of us are now probably using some sort of a Rust-based tool chain, whether SWC or Turbopack soon once it's released, or Vite's new Rolldown, which is their Rust replacement for Rollup. As the tooling evolves and matures, I think the modularity piece is really important there.
Alex Booker (23:13):
Let's talk about what else is new in React 19 because we spent quite a bit of time on compiler as we should, being pretty much the flagship feature. Talk to me a little bit about Actions and the role they play in React 19. I've heard of Actions in videos and on podcasts for well over a year now.
(23:32):
So, while they might be approaching an RC and a stable version, as I understand it, they've been coming for a long time. What are they and what problem do they solve in React?
Dev Agrawal (23:41):
Actions are very much supposed to be a replacement for event handlers like button onClick or form onSubmit, things like that. The problem with event handlers is that they're synchronous. You give the event handler a function, and React will trigger that function and that's it. Everything else that happens is fully in our control. And a lot of times what we do in those event handlers is asynchronous things.
(24:05):
For example, we go talk to a server. Talking to the server is probably the default thing to do. But more often than not, we are doing something asynchronous in those event handlers. So, Actions are kind of a new convention to define those things. They can directly accept asynchronous functions. So, you can pass in an async function and what React will do is that it'll, by default, run it inside a transition.
(24:30):
So, Actions is basically, you can think of it as syntax sugar over transitions, or React transitions. If you haven't come across React transitions, it's very much a feature that React has been working on for ages. You might have heard of concurrent rendering or concurrent mode, concurrent features. Suspense and transitions are kind of like the two sides of a coin that help you use the concurrent features that React has.
(24:53):
And the idea is that the thing that you would put inside the transition is an asynchronous function. So, you would say startTransition, which is a function that you would import from React. And inside startTransition, you would have an asynchronous function. Usually, when we have asynchronous things, we have things like loading states or error states or request cancellation, for example.
(25:14):
If I click on a button twice really quickly, we want the first request to be canceled so that the second one can take place. Or if we are updating some state at the end of the asynchronous task, we want to make sure that if I click on the button twice, I only want the second one to update my state. So, we don't want race conditions. So, a lot of these tasks that we had to manually handle in user land, and of course we had libraries like React Query, TanStack Query, SWR.
(25:39):
A lot of these libraries helped us, but those libraries were a lot of additional infrastructure that were built on top of React's model to help us address this. Suspense and transitions kind of build that into React itself so that we have a lot less overhead to think about when we are doing these things.
Alex Booker (25:55):
So, they're called transitions. What are they transitioning from and what are they transitioning to?
Dev Agrawal (26:00):
Let's say that I have a to-do list and I type in a new to-do and I hit submit. Now what's happening here is we are reaching out to a server, sending that add request or whatever. We're coming back to the client and maybe we are revalidating some data to get the new list of to-dos. And at the end, we have our new list of to-dos on the screen.
(26:20):
So, a transition is meant to encapsulate that entire asynchronous process. You can maybe also think of it as transactions. Transactions probably would have been a better term for them.
Alex Booker (26:30):
There's still time. There's still time, Dev. The RC isn't out yet.
Dev Agrawal (26:33):
Yeah, that's fair, but I don't think they're going to change this one at this point. Also, transitions have actually been around since, I believe, React 18. They might have been introduced earlier. The from of a transition is the moment that asynchronous fetch or the asynchronous task starts, which in this case would be me hitting enter or clicking on the submit button or basically submitting this form.
(26:56):
And the end of the transaction is getting that new list of to-dos on my screen. So, transitions are a way for us to tell React that this state update can be delayed or it can happen in the background. For example, when I hit enter, I can still interact with my application while React is doing its asynchronous work in the background, it's getting the new data and it's rendering the new screen, but it's doing that in the background.
(27:22):
It doesn't block the thread or it doesn't bring it onto the screen or it doesn't stop me from interacting, which means if I immediately hit enter again or if I type in a new to-do and I quickly hit enter, it can just cancel that background work of rendering that new to-do list. And it can start a new one, which means at the end of the transition, I'm going to have both my new to-dos instead of just one of them.
(27:46):
And Actions are just something that give us a better API to do with. We don't have to call startTransition manually. We can just say formAction this asynchronous function here, and by default, it turns into a transition.
Alex Booker (27:59):
Okay, brilliant explanation. I'm really following you here. But help me close the loop here. How do Actions in React 19 relate to transitions?
Dev Agrawal (28:09):
The first thing that Actions are, are a syntax sugar, kind of. If you take a function and pass it into a formAction property or a button formAction property, instead of the onSubmit event or the onClick event, it becomes a transition by default, again, instead of us having to call startTransition and manage that transition state on our own. The second thing is React Core team really wants us to change the convention around how we create custom events.
(28:38):
So, if in my to-do app, I have a to-do component that might have an onDelete button or onDelete event, which is where we might be handling the deletion of the to-do, or an onCheck, onToggle, onEdit, all of these custom things that we want to do with components, we expose them as events. The idea is that we should expose these as Actions instead, or we should rename this to lead action or submit action.
(29:03):
So, this now becomes our vocabulary whenever we are talking about asynchronous things that a component could be doing.
Alex Booker (29:11):
So, whereas currently with React, if I'm creating a form, I would say onSubmit equals and I'd pass a function to execute when the function is submitted onSubmit. But with React 19, I would not use onSubmit. I would say action equals and pass a function to execute when the form is submitted. I guess with form, onSubmit is the obvious candidate.
(29:33):
Maybe for button, onClick is the obvious candidate as well. But what if there are multiple actions that could result in a transition? Is it literally called just action, or do you differentiate the actions with check action, delete action, that kind of thing?
Dev Agrawal (29:48):
Yeah. So, for custom actions, you probably want to have separate actions for different things that you want to do with components. The action prompt that we pass into a form or a button, that's just a way for us to use that action with ReactDOM. So, if you were using React Native, you probably wouldn't be using form or button. You'd be using whatever components React Native exposes and using the action property there.
(30:10):
And the other separation is that if you're handling a form submit event like onSubmit, you get the event object and then you have to call event.preventDefault, and then you have to do additional things in whatever you are doing. That's something that now React takes care of. And instead of giving you the event, it gives you a form data object, which is React trying to be more web native and use the web standards.
(30:34):
So, instead, now you get the form data object that has all the inputs of that form. And one other nice feature is related to server-side rendering and hydration. Right now, if you attach events on your elements, you have to wait for the entire screen to get hydrated, the entire page to be hydrated, before you can do any interactions.
(30:55):
So, this is a limitation of event handlers currently, which is that if you're using an SSR framework, you get all the html, but you can only start interacting with your page, with your UI once everything is hydrated. What Client Actions allow us to do is that if you try to interact with your UI before it's hydrated, React is going to record that or it's going to remember what you did.
(31:18):
And once the component is finished hydrating, it's going to call your actions then. So, it's going to cue those up while the page is still hydrating. And then, once it has hydrated, once it knows exactly which function to call, it's going to call it. So, you're not going to miss any interactions while your page is hydrating.
Alex Booker (31:36):
That's so cool. There are two types of actions, right? There are Server Actions, which you might use within the context of a meta-framework so that that action could actually be a function that runs on the server and accesses the database maybe or some backend session states.
(31:51):
And then, there are Client Actions which are basically what we've been talking about, which is a replacement for those event handlers that we might have used previously. Is there a benefit in them sharing the same name? Are they almost compatible in a way?
Dev Agrawal (32:05):
Yeah. So, Client Actions and Server Actions are semantically very similar. And now, they're going to work in basically the same way. The only difference is that we now have this use server directive, which as soon as we put it inside any Client Action, it becomes a Server Action. And obviously, it gives us the benefit of directly interacting with any server resources that we might have on the server.
(32:27):
And the other benefit there is that now that this action lives on the server, instead of living on the client, React doesn't have to wait till hydration to trigger it. If you submit a form that talks to a Server Action, it can just immediately send an HTTP request to your server, which is going to trigger that action, instead of waiting to finish hydration.
(32:46):
So, Server Action now just becomes a Client Action, with a couple additional server related niceties. And all the other behavior semantics, they stay the exact same, which is that it's going to happen in the background. React is going to handle race conditions or cancellations, if there are any. And it's going to make sure that if any of your data has been invalidated or needs to be re-fetched after your action, it's going to happen in the transition as well.
(33:12):
So, it's going to render the new version of your UI in the background with all the new data and only show it to the user once everything is consistent and ready.
Alex Booker (33:19):
So, that's actions in React 19. I'm going to switch over to another topic, but is also related to forms because actions are often used with forms. But there are a couple of other new hooks in React 19, I think, to do with forms which are useFormState and useFormStatus. Could you quickly tell us about those?
Dev Agrawal (33:39):
So, we just talked about formAction and the button formAction properties, and these are ways for us to define actions that are directly interactive with the DOM. The new hooks, useFormState, which is now has been renamed to useActionState-
Alex Booker (33:54):
Oh, really?
Dev Agrawal (33:56):
... because it has to do with actions. useFormStatus is still useFormStatus because that's very much designed to be used inside a form as a context consumer. But let me talk about useActionState real quick. So, useActionState is a way to use a consume an action just inside your JavaScript code, instead of passing it into a form or inside a button.
(34:16):
And what that allows us is it gives us access to two extra things. The first one is an isPending flag or an isPending Boolean value, which basically tells us that this action is currently... someone has triggered this action, it's doing some work. Or this action has finished execution and we are now in a consistent state. So, you can use it to show any loading spinners or disable anything that you might want to.
(34:41):
So, that's what the isPending gives us, which we don't have access to directly if we just pass the action directly into the form. The other thing it gives us is access to the return value of the action. Usually, an action is just supposed to do some asynchronous work and then set some new states somewhere so that you can get your new UI.
(35:02):
But if you return something from an action, like let's say you might want to return some error values or any validation errors that might have happened, so you get access to that using the useActionState hook. There are three return values to the useActionState hook, a way to know if that action is pending or not, the return value from that action, and then obviously a way to trigger it synchronously.
Alex Booker (35:24):
And it's just quite clean to use, isn't it, compared to the ways we might have handled something like this previously. Even though it's a React 19 feature, could I call it production ready in meta-frameworks like Next, I guess? Because that's where I've been using it. And it's just very pleasant, I think, to set up your forms in this way and have access to pretty much all the information you need to implement your form logic.
Dev Agrawal (35:44):
Yeah, I think Actions and suspense and all these new concurrent features are kind of a big departure from how most people use React today. So, it takes a little while to get it incorporated into our workflows. But how I've been thinking about these concurrent features is that if you're building any sort of asynchronous UI, which all of us are doing actually, we are talking to a database, we are talking to browser APIs, we are talking to file systems, anything like that.
(36:12):
We're doing asynchronous work in our UI. Up until now, it has been kind of a pain to handle all those asynchronous coordination with the regular synchronous React that we have. Now, with the concurrent features, consistency has become the default, which means if we don't use any of these new fancy hooks like useActionState or useOptimistic, as long as we just keep using Suspense and formActions like React wants us to, we will always have consistent and bug-free UI.
(36:42):
We won't have inconsistent glitches. We won't have tearing. We won't have, okay, one piece of state here shows something, but here you have something else. We won't have things like race conditions. So, all of those things have been eliminated in the fundamental model that we are using. And these new hooks are basically a way for us to hook into these processes and show things like optimistic UI or loading skeletons.
Alex Booker (37:06):
You're doing such a fantastic job explaining these things with only a voice really because we don't have any diagrams or code or anything for people to look at. But the real objective of this episode, which I think we've succeeded at, I hope, the listener will be the ultimate judge of course. But I think we've succeeded in giving that overview and in giving directionally information about what these features do so that now someone listening can go and learn more about them.
(37:30):
And to that end, I wanted to ask you in closing, because unfortunately we are at the end of time, what are some good resources to learn more about these things if someone listening is sufficiently excited to go a bit deeper and learn the latest React features?
Dev Agrawal (37:42):
React.dev is always going to be a fantastic resource. There was a period of time where the React docs were heavily outdated, but I think all the work that the React Core team has put into building the new docs website has been amazing. So, honestly, just check out the React documentation. Other than that, I think some of the talks at React Conf have been absolutely amazing at explaining these things.
(38:07):
For example, if you want to understand how Actions, transitions, concurrent React, how that works, check out the talk by Sam Selikoff at React Conf. What he basically does is he has this checkout page UI that's written in the old way of React, without any concurrent features being used, and he step by step converts it using all the new React features.
(38:28):
And it's such an amazing talk because it not only shows the power of the new model, but it shows how much it simplifies the code. And not only does it simplify the code, but it eliminates so many issues or errors that were so easy to get into, so easy footguns that we always fall into with building these UIs.
Alex Booker (38:46):
We'll definitely link those in the show notes. And I love that you mentioned the React.dev website because we had Rachel Nabors on a few weeks ago, who played a role in getting that off the ground. I'll link the episode in the show notes as well.
Dev Agrawal (38:57):
Of course, yeah.
Alex Booker (38:58):
Dev Agrawal, thank you so much for your time.
Dev Agrawal (39:00):
Of course. Thanks for having me on again.
Alex Booker (39:02):
See you soon.
Jan Arsenovic (39:04):
That was The Scrimba Podcast, Episode 163. Thanks for listening. And if you made it this far, please consider subscribing. You can find this show wherever you get your podcasts, and since December, that also includes YouTube. Make sure to check out the show notes for the resources mentioned in this episode. And if you're enjoying our show and you'd like to support us, the best thing you can do is telling somebody about it.
(39:30):
You can do it in person, you can do it on Discord, you can do it on socials. You can also leave us comments on YouTube or you can leave us a rating or a review in your podcast app of choice. So, if you're on Spotify, maybe you could give us five stars. Or if you're on Apple Podcast, you can write about something that you like about our podcast.
(39:52):
And yes, we read your social media post, your comments and your reviews on the show. So, you might get a shout-out. The Scrimba Podcast is hosted by Alex Booker and produced by me. I'm Jan, the producer. You can find both of our Twitter handles in the show notes. Once again, thanks for listening. Keep coding and we'll see you in the next one.