React 19: Actions, use(), useOptimistic, and What Actually Changed

React 19 is a foundational shift in how you handle async mutations, data loading, and optimistic UI - here is every new API with real code examples.

Mahmudul Haque Qudrati — CEO & ML Engineer at Pristren

Mahmudul Haque Qudrati

CEO & ML Engineer

March 12, 2026
7 min read
React 19: Actions, use(), useOptimistic, and What Actually Changed

What Is React 19?

React 19 is the first major version since React 18 and it rewires how you think about async state. Instead of wiring up useEffect + useState + error boundaries manually, React 19 gives you first-class primitives for the entire async lifecycle.

React Actions

Actions are async functions that React knows about. When you pass them to <form action={fn}> or use them with the new hooks, React handles pending state, errors, and optimistic updates automatically.

tsx
import { useActionState } from "react";

async function submitForm(prevState: State, formData: FormData) {
  const result = await saveToServer(formData.get("name") as string);
  if (!result.ok) return { error: "Save failed" };
  return { success: true };
}

function Form() {
  const [state, action, isPending] = useActionState(submitForm, null);

  return (
    <form action={action}>
      <input name="name" disabled={isPending} />
      {state?.error && <p>{state.error}</p>}
      <button type="submit" disabled={isPending}>
        {isPending ? "Saving..." : "Save"}
      </button>
    </form>
  );
}

The use() Hook

use() is the escape hatch that lets you read a Promise or Context inside the render function. Unlike other hooks, it can be called inside loops and conditionals.

tsx
import { use, Suspense } from "react";

function UserCard({ userPromise }: { userPromise: Promise<User> }) {
  const user = use(userPromise); // suspends while pending
  return <div>{user.name}</div>;
}

// In the parent:
<Suspense fallback={<Skeleton />}>
  <UserCard userPromise={fetchUser(id)} />
</Suspense>

Reading context with use() is useful inside conditional branches:

tsx
if (needsTheme) {
  const theme = use(ThemeContext); // valid  -  hooks rules relaxed for use()
}

useOptimistic()

Show the result of a mutation instantly while the server request is in flight:

tsx
import { useOptimistic, useTransition } from "react";

function TaskList({ tasks }: { tasks: Task[] }) {
  const [optimisticTasks, addOptimistic] = useOptimistic(
    tasks,
    (state, newTask: Task) => [...state, newTask]
  );
  const [, startTransition] = useTransition();

  function handleAdd(title: string) {
    const newTask = { id: crypto.randomUUID(), title };
    startTransition(async () => {
      addOptimistic(newTask);         // UI updates immediately
      await createTask(title);        // server catches up
    });
  }

  return <ul>{optimisticTasks.map(t => <li key={t.id}>{t.title}</li>)}</ul>;
}

Refs as Props - No More forwardRef

In React 19, functional components accept ref as a regular prop. The forwardRef wrapper is no longer needed (and will be deprecated in a future minor):

tsx
// Before (React 18)
const Input = forwardRef<HTMLInputElement, Props>((props, ref) => (
  <input {...props} ref={ref} />
));

// After (React 19)
function Input({ ref, ...props }: Props & { ref?: Ref<HTMLInputElement> }) {
  return <input {...props} ref={ref} />;
}

Server Actions Are Stable

Server Actions work in both Server and Client Components. In a Client Component, import a Server Action and call it like a regular async function:

tsx
"use client";
import { deleteTask } from "@/app/actions";

function DeleteButton({ id }: { id: string }) {
  return (
    <button onClick={() => deleteTask(id)}>Delete</button>
  );
}

The React Compiler (Formerly Forget)

The React Compiler - previously called React Forget - is in beta for React 19. It automatically memoizes components and values, eliminating the need for manual useMemo, useCallback, and memo() in most cases.

Enable it in Next.js 15:

typescript
// next.config.ts
export default {
  experimental: {
    reactCompiler: true,
  },
};

Migration Steps

  1. pnpm add react@19 react-dom@19
  2. Replace useFormState with useActionState
  3. Remove forwardRef - pass ref as a prop directly
  4. Replace manual optimistic state patterns with useOptimistic()
  5. Run the React 19 codemod: npx codemod@latest react/19/migration-recipe

References: React 19 blog · migration guide

#react-19#actions#use()#useoptimistic#server-components

One AI engineering post, weekly

LLM benchmarks, prompt techniques, and token-cost breakdowns, delivered to your inbox.

Comments

Have a question or something to add? Sign in to join the discussion.

Mahmudul Haque Qudrati — CEO & ML Engineer at Pristren

Mahmudul Haque Qudrati

CEO & ML Engineer

Visionary technologist, software engineer, and machine learning specialist. Founder and CEO of Pristren, directing engineering teams that ship production-grade AI/ML pipelines, mission-critical full-stack applications, and developer tooling. Creator of Zlyqor, the unified team workspace platform. Author of 540+ technical guides and benchmark research reports on large language models, agentic workflows, Model Context Protocol (MCP), and modern web stacks.

PristrenZlyqor