
Introduction to React 19: Actions, Forms, and React Server Components
One of the most developer-facing changes in React 19 is the introduction of Actions – a new pattern for handling form submissions and mutations – and the stabilization of React Server Components for broader use. These go hand-in-hand in enabling more seamless full-stack React apps.
What Are Actions in React?
What Are “Actions”? Actions in React 19 provide a streamlined way to handle events like form submissions by using async functions as form actions instead of onSubmit handlers. In practical terms, you can now write:
async function saveData(formData) { // e.g., send to server or update state } // ... <form action={saveData}> {/* form fields... */} <button type="submit">Save</button> </form>
Here, the
action
attribute of the form points to an async function (client-side or server-side). When the user submits, React will call that function with aFormData
object, automatically handle the submission process (preventing default, etc.), and manage loading states and errors for you (What’s new in React 19 - Vercel) (What’s new in React 19 - Vercel). This is a radical shift from the manualonSubmit
+ setState approach. Under the hood, React treats form Actions similarly to a transition: the submission is a transition that can be awaited.Client Actions: In a client-only context, the pattern replaces having an onClick/onSubmit that sets
isLoading
. Instead, if you call an async state update insidestartTransition
, React will markisPending
for you until it finishes (React v19 – React) (React v19 – React). This means the<button>
will automatically be disabled if you bind itsdisabled
to the form’s pending state, etc. The React team’s example shows how less code is needed: “In React 19, we’re adding support for using async functions in transitions to handle pending states, errors, forms, and optimistic updates automatically.” (React v19 – React).Server Actions: More powerfully, React 19 allows defining actions that run on the server – essentially Server Functions that can be invoked from the client without writing a separate API. This is enabled by the
'use server'
directive. For example, in Next.js (which quickly adopted this pattern), you can create a fileactions.js
:'use server'; export async function createPost(data) { // this code runs on server (Node.js), can access DB, etc. await db.insert(data); }
And in your component (marked
'use client'
), use it as<form action={createPost}>
(What’s new in React 19 - Vercel) (What’s new in React 19 - Vercel). When the form is submitted, React will serialize the form data, send it to an endpoint behind the scenes, runcreatePost
on the server, and stream the result back. This mechanism removes the need to manually create fetch handlers or API routes for simple cases. It’s conceptually similar to frameworks like Remix’s actions, or RPC-style mutations. In React 19, this is available for frameworks to leverage (Next.js 13.4+ calls them “Server Actions”). It’s important to note that these server actions run in a special context – you need a server environment (Node, Deno, etc.) to support them, so they’re primarily used in frameworks, not in plain CRA apps.
New Hooks for Form State
New Hooks for Form State: Alongside Actions, React 19 introduced a trio of Hooks to make building UI around forms easier:
-
useActionState
: Manages form submission state and result data on the client (What’s new in React 19 - Vercel) (What’s new in React 19 - Vercel). For a given Action function,useActionState(actionFn, initialState)
returns[state, formAction, pending]
. You useformAction
as the function to pass to<form action={...}>
, andstate
will contain things like the response or any data the action returned (for example, a success message), andpending
is a boolean for whether the action is in-flight (What’s new in React 19 - Vercel) (What’s new in React 19 - Vercel). This hook essentially gives you a convenient state machine for each form without writing reducers or manual effect logic. In a sign-up form example,state
could hold an error or success message from the server, andpending
drives a “Submitting...” UI on the button (What’s new in React 19 - Vercel). -
useFormStatus
: A lighter weight hook to check the status of the nearest parent form’s submission (What’s new in React 19 - Vercel) (What’s new in React 19 - Vercel). It returns an object withpending
(and possibly error in the future). This is useful when you have nested components inside a form that need to know if the form is currently submitting. For instance, a child SubmitButton component can callconst status = useFormStatus();
and then disable itself ifstatus.pending
is true (What’s new in React 19 - Vercel) (What’s new in React 19 - Vercel). It’s a way to get contextual form state without prop drilling. Notably, it only works inside a form (React will error if you call it otherwise). The React docs note thatuseFormStatus
is handy for shared form components or multiple forms on the page, whereasuseActionState
is more for when you need to manage form data state in addition to pending status (What’s new in React 19 - Vercel). -
useOptimistic
: This hook helps implement optimistic UI updates, which means updating the UI immediately as if an action succeeded, and reconciling later when the real result comes back.useOptimistic(initialState, updater)
returns a tuple[optimisticState, addOptimisticUpdate]
(What’s new in React 19 - Vercel) (What’s new in React 19 - Vercel). You can calladdOptimisticUpdate(update)
to immediately update the local optimistic state using yourupdater
function, and then still call the real action. A classic use-case is a chat app: when you send a message, you want to show it in the UI instantly, without waiting for the server confirmation. UsinguseOptimistic
, you maintain an array of messages, and on form submit, you add the new message to that array optimistically, then call the server action to actually send it (What’s new in React 19 - Vercel) (What’s new in React 19 - Vercel). If the server action fails, you could roll back or show an error (that part you handle in the action’s promise rejection). The key benefit is separating the local UI state from the server state in a straightforward way. The code ends up much cleaner than manually setting state, then resetting it if an error occurs. React’s docs show that once the server action completes, you typically just ignore the optimistic entry because the server’s response (or a refetch) will reconcile the true state (What’s new in React 19 - Vercel) (What’s new in React 19 - Vercel).
Together, these hooks make form handling in React 19 far more ergonomic. You get built-in solutions for a lot of things that used to require external libraries or a bunch of boilerplate (think: form libraries, loading spinners, disabling buttons, optimistic UI, error handling).
-
React Server Components (Stable)
React Server Components (Stable): React 19 is the first version where React Server Components (RSC) are deemed stable and not expected to have breaking changes going forward (React 19 RC with stable Server Components and React Compiler). RSCs were an experimental feature in React 18 that allow you to render components on the server at build or request time and stream them to the client, without sending a full HTML page. In React 19, the core support for RSC is solidified. This means frameworks like Next.js 13/14 can rely on RSC in production. For developers, the benefit of RSC is that you can fetch data and render markup on the server for parts of your app, then seamlessly integrate it into a client React tree. They enable 0kb JS for those components on the client, since the UI is essentially serialized and hydrated as a static output.
With React 19’s release candidates, the React team signaled that RSC’s fundamental API (the way you mark modules with
'use server'
or'use client'
, how you pass props, etc.) is now stable (React 19 RC with stable Server Components and React Compiler) (React 19 RC with stable Server Components and React Compiler). So you can invest in the RSC architecture without fear of it changing under you in React 20. Many full-stack React frameworks are embracing this:- Next.js App Router is built entirely on RSC + Actions. As of Next 13.4 and definitely in Next 15 (which uses React 19 under the hood), you write React components for your pages and choose on a per-component basis whether they run on server or client by adding the
"use server"
or"use client"
directive at the top of the file. Next’s routing conventions then leverage React 19’s new capabilities to implement data fetching, caching, and mutations (forms) in a more React-native way rather than custom APIs. - Expo and React Native: At React Conf 2024, there was a demo of RSC working in an Expo (React Native) context (React 19 RC with stable Server Components and React Compiler) (React 19 RC with stable Server Components and React Compiler). This hints that the RSC paradigm isn’t just for web – it can be used to render components on a server that are eventually used in a native app as well. It’s an advanced use-case, but imagine server-rendering some data-heavy list in a mobile app and sending it precomputed to the client to save on device processing – RSC makes that possible.
- Remix and React Router: Remix’s loader/action model parallels a lot of what React 19 offers natively (loading data on the server, handling forms). The React Router team (which maintains Remix now) has been aligning Router’s features with React 19 so that you can gradually adopt things like
<Form>
with either Remix’s actions or React’s actions. React Router v6.14+ (and the upcoming v7) explicitly supports React 19 and lets you mix and match “data routers” with React’s own capabilities (React Router Home | React Router). We’ll touch more on this in Ecosystem Updates.
- Next.js App Router is built entirely on RSC + Actions. As of Next 13.4 and definitely in Next 15 (which uses React 19 under the hood), you write React components for your pages and choose on a per-component basis whether they run on server or client by adding the
Full-Stack Directives –
"use client"
and"use server"
: These file-level directives deserve a mention. They’re not React APIs per se, but strings that serve as cues for bundlers. React 19 solidified their role."use client"
at the top of a file means the file (and its exports) must be included in the client-side bundle, whereas"use server"
indicates the file exports server-only functions (like our server Actions above) (React 19 is on its way — What’s changing? | by Hvardhan | Medium). They demarcate the boundary between client and server code in React’s Module graph. This is how frameworks know how to split your code for RSC and Actions. For example, Next.js will bundle"use client"
components separately and ensure they are loaded in the browser, while"use server"
exports become API endpoints. If you’re doing any full-stack React, you’ll encounter these directives. React 19 doesn’t change how you write them, but it cements their usage as standard. The React docs liken"use client"
to telling the bundler to create a script tag (for that module) and"use server"
to telling it to create a background function (exposed via an endpoint) (React 19 is on its way — What’s changing? | by Hvardhan | Medium). This mental model can help – it’s a bit like writing serverless functions that are seamlessly callable from your React components.
Conclusion
In summary, React 19’s introduction of Actions and the maturation of Server Components means that React (especially when used with frameworks) is moving toward a more integrated full-stack experience. You can handle user input, mutate data, and bridge between client UI and server logic with significantly less boilerplate. As one Medium post aptly put it: “Actions will revolutionize how we interact with forms. They allow you to integrate actions with the <form>
HTML tag, replacing the traditional onSubmit event.” (New Features in React 19 — Actions | by VageeshaW - Medium). This also has a ripple effect: state management for transient form state might become simpler (or even unnecessary in some cases), and patterns that were once complex (like optimistic updates) are now first-class citizens. For developers, the learning curve is mostly about embracing these new patterns and understanding how data flows (especially with server actions). But early adopters report that it dramatically simplifies code for forms and mutations – one example from Vercel’s blog showed a Todo app where adding an item went from multiple state hooks to just an async function
action that updates state and a simple form in JSX (What’s new in React 19 - Vercel) (What’s new in React 19 - Vercel).
Date: