Tous les articles
ReactFrontendJavaScript

React 19: use(), Server Actions, useOptimistic, and ref as a Prop

//
·8 min de lecture

React 19 stabilises Server Actions and Server Components, introduces the use() hook for promises and context, ships useOptimistic for instant UI feedback, and eliminates forwardRef — ref is now a regular prop.

React 19 released on December 5, 2024 and is the most significant major version since hooks in React 16.8. The release graduates Server Components and Server Actions from experimental to stable, introduces three new hooks, and simplifies several long-standing patterns.

>use() — read promises and context anywhere

use() is a new hook that suspends a component until a promise resolves, or reads a context value. Unlike useContext, it can be called conditionally.

TypeScript
import { use, Suspense } from 'react';

// Read a promise — component suspends until resolved
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
  const user = use(userPromise); // throws the promise → Suspense catches it
  return <h1>{user.name}</h1>;
}

// Read context conditionally (unlike useContext)
function ThemedButton({ primary }: { primary: boolean }) {
  if (primary) {
    const theme = use(ThemeContext); // ✓ conditional call is allowed
    return <button style={{ background: theme.primary }}>Click</button>;
  }
  return <button>Click</button>;
}

// Usage with Suspense
<Suspense fallback={<Spinner />}>
  <UserProfile userPromise={fetchUser(id)} />
</Suspense>

>Server Actions — stable

Server Actions are now stable. They are async functions marked with "use server" that run on the server and can be called directly from client components — no API route needed.

TypeScript
// actions.ts
'use server';
import { revalidatePath } from 'next/cache';
import { db } from '@/lib/db';

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string;
  await db.post.create({ data: { title } });
  revalidatePath('/posts');
}

// Client component — call the action directly
'use client';
import { createPost } from './actions';

export function NewPostForm() {
  return (
    <form action={createPost}>
      <input name="title" placeholder="Post title" />
      <button type="submit">Create</button>
    </form>
  );
}

>useOptimistic — instant UI feedback

useOptimistic lets you show an optimistic UI state while a Server Action or async operation is in progress, then automatically reverts on error.

TypeScript
'use client';
import { useOptimistic, useTransition } from 'react';
import { toggleLike } from './actions';

function LikeButton({ postId, liked, count }: LikeButtonProps) {
  const [optimisticLiked, setOptimisticLiked] = useOptimistic(liked);
  const [optimisticCount, setOptimisticCount] = useOptimistic(count);
  const [isPending, startTransition] = useTransition();

  const handleClick = () => {
    startTransition(async () => {
      setOptimisticLiked(!liked);
      setOptimisticCount(liked ? count - 1 : count + 1);
      await toggleLike(postId); // actual server call
    });
  };

  return (
    <button onClick={handleClick} disabled={isPending}>
      {optimisticLiked ? '❤️' : '🤍'} {optimisticCount}
    </button>
  );
}

>ref as a prop — no more forwardRef

⚠ BREAKINGforwardRef is deprecated in React 19. Pass ref as a regular prop instead.

TypeScript
// ✗ React 18 — forwardRef required
const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => (
  <input {...props} ref={ref} />
));

// ✓ React 19 — ref is a regular prop
function Input({ ref, ...props }: InputProps & { ref?: React.Ref<HTMLInputElement> }) {
  return <input {...props} ref={ref} />;
}

// Usage unchanged
const inputRef = useRef<HTMLInputElement>(null);
<Input ref={inputRef} placeholder="Search..." />

>Context as a provider

TypeScript
const ThemeContext = createContext<Theme>({ mode: 'light' });

// ✗ React 18
<ThemeContext.Provider value={{ mode: 'dark' }}>
  {children}
</ThemeContext.Provider>

// ✓ React 19 — Context itself is the provider
<ThemeContext value={{ mode: 'dark' }}>
  {children}
</ThemeContext>

>New Document Metadata API

TypeScript
// React 19 natively hoists <title>, <meta>, <link> to <head>
// No need for react-helmet or next/head in pure React apps
function BlogPost({ post }: { post: Post }) {
  return (
    <>
      <title>{post.title}</title>
      <meta name="description" content={post.excerpt} />
      <link rel="canonical" href={`https://example.com/posts/${post.slug}`} />
      <article>{post.content}</article>
    </>
  );
}

>Upgrade from React 18

bash
npm install react@19 react-dom@19

# Automated codemod handles most changes
npx codemod@latest react/19/migration-recipe

# What the codemod handles:
# ✓ forwardRef → ref prop
# ✓ Context.Provider → Context as provider
# ✓ ReactDOM.render → createRoot (if not already done)
# ✓ Deprecated string refs removed

# Run your test suite — React 19 has strict mode improvements
# that may surface latent double-render issues