React 19

Flashcard 1/13
What is the use API in React 19, and how does it differ from other hooks?

All 13 React 19 flashcards

Every question in this free section, with its full answer — open one to check yourself, or use the card view above to drill them in order.

What is the use API in React 19, and how does it differ from other hooks?

use reads the value of a resource — either a Promise or a Context. Given a Promise, it suspends the component until the Promise resolves (integrating with Suspense and error boundaries); given a Context, it returns the context value like useContext.

Unlike every other hook, use can be called conditionally and inside loops or if blocks. The Promise it reads should come from a Server Component or a cache — don't create a new Promise during the render of a Client Component, since that makes a fresh Promise on every render.

import { use, Suspense } from "react";

function Message({ messagePromise }) {
  const text = use(messagePromise); // suspends until resolved
  return <p>{text}</p>;
}

function Container({ messagePromise }) {
  return (
    <Suspense fallback={<p>Loading...</p>}>
      <Message messagePromise={messagePromise} />
    </Suspense>
  );
}

// use() also reads context, and may be called after an early return:
function Heading({ children }) {
  if (children == null) return null;
  const theme = use(ThemeContext);
  return <h1 style={{ color: theme.color }}>{children}</h1>;
}
What does the useActionState hook do in React 19, and what is its signature?

useActionState manages the state produced by a form action. It returns [state, formAction, isPending]: the current state, a wrapped action you pass to a <form> (or a button's formAction), and a pending flag while the action runs.

import { useActionState } from "react";

async function submit(previousState, formData) {
  const email = formData.get("email");
  const res = await subscribe(email);
  if (!res.ok) return { error: "Something went wrong" };
  return { success: true };
}

function Signup() {
  const [state, formAction, isPending] = useActionState(submit, {});

  return (
    <form action={formAction}>
      <input name="email" type="email" />
      <button disabled={isPending}>
        {isPending ? "Submitting..." : "Sign up"}
      </button>
      {state.error && <p>{state.error}</p>}
      {state.success && <p>Thanks!</p>}
    </form>
  );
}

The action receives the previous state as its first argument and the form's FormData as its second; its return value becomes the new state. This replaces manual useState + submit-handler + loading-flag wiring, and works with both client and Server Actions. (It was the experimental useFormState before React 19.)

What is useFormStatus in React 19, and where must it be called?

useFormStatus (from react-dom) reads the submission status of the parent <form>. It returns { pending, data, method, action } and must be called from a component rendered <em>inside</em> that form — it reads the form via context, so it can't be used in the same component that renders the <form>.

import { useFormStatus } from "react-dom";

function SubmitButton() {
  const { pending } = useFormStatus();
  return <button disabled={pending}>{pending ? "Saving..." : "Save"}</button>;
}

function ProfileForm({ action }) {
  return (
    <form action={action}>
      <input name="name" />
      <SubmitButton /> {/* reads the form's pending state */}
    </form>
  );
}

It lets reusable submit buttons and inline indicators react to submission without prop-drilling a pending flag. Use useFormStatus for shared form controls; use useActionState's isPending when you already have it in the form component.

How does the useOptimistic hook work in React 19, and when would you use it?

useOptimistic shows a temporary, optimistic UI while an async action is in flight. It returns [optimisticState, addOptimistic]; you call addOptimistic with the optimistic value, and React automatically reverts to the real state once the action settles.

import { useOptimistic } from "react";

function Thread({ messages, sendMessage }) {
  const [optimisticMessages, addOptimistic] = useOptimistic(
    messages,
    (current, newText) => [...current, { text: newText, sending: true }]
  );

  async function formAction(formData) {
    const text = formData.get("message");
    addOptimistic(text);      // show it immediately
    await sendMessage(text);  // real request; state syncs when done
  }

  return (
    <>
      {optimisticMessages.map((m, i) => (
        <div key={i}>{m.text} {m.sending && "(sending...)"}</div>
      ))}
      <form action={formAction}><input name="message" /></form>
    </>
  );
}

It must run inside a transition or action (e.g. a form action) so React knows when the async work finishes. The second argument is a reducer (currentState, optimisticValue) => newState that merges the optimistic update.

What are form Actions in React 19 (passing a function to <form action>)?

In React 19 you can pass a function directly to a form's action prop (and to a button's formAction). React calls it with the form's FormData on submit, automatically wraps it in a pending transition, and resets an uncontrolled form on success.

function Search() {
  async function search(formData) {
    const q = formData.get("q");
    await runSearch(q);
  }

  return (
    <form action={search}>
      <input name="q" />
      <button>Search</button>
    </form>
  );
}

Actions compose with useActionState (for returned state) and useFormStatus (for pending UI). When the action is a Server Action ("use server"), the form works even before JavaScript loads — progressive enhancement.

How did ref handling change for function components in React 19?

In React 19, function components can receive ref as a regular prop. forwardRef is no longer required (and is now deprecated) — you just destructure ref alongside your other props.

// React 19
function TextInput({ placeholder, ref }) {
  return <input ref={ref} placeholder={placeholder} />;
}

function Form() {
  const inputRef = React.useRef(null);
  return <TextInput ref={inputRef} placeholder="Name" />;
}

// Before React 19 you needed:
// const TextInput = forwardRef(({ placeholder }, ref) => ...);

A codemod can migrate existing forwardRef components. forwardRef still works for now, but new components should take ref as a prop.

What new capability do ref callbacks have in React 19?

A ref callback can now return a cleanup function, like useEffect. React runs the cleanup when the element unmounts (or the ref changes), instead of calling the callback again with null.

function Chart() {
  return (
    <div
      ref={(node) => {
        const chart = createChart(node);
        return () => chart.destroy(); // cleanup on unmount
      }}
    />
  );
}

This makes imperative setup/teardown on a DOM node cleaner. Because returning a value now signals a cleanup function, ref callbacks must not implicitly return anything else — avoid concise arrow bodies that return a non-cleanup value.

How can you render a Context provider in React 19 without .Provider?

In React 19 you can render <Context> directly as the provider instead of <Context.Provider>. The old form still works but is being deprecated, and a codemod can migrate it.

const ThemeContext = createContext("light");

function App() {
  return (
    <ThemeContext value="dark">
      <Page />
    </ThemeContext>
  );
}

// Read it with use() or useContext():
function Page() {
  const theme = use(ThemeContext);
  return <div className={theme} />;
}
What are React Server Components, and how do they differ from Client Components?

Server Components render on the server (at build time or per request) and ship <em>no</em> JavaScript to the browser. They can be async and fetch data or access server resources directly. They can't use state, effects, or browser-only APIs.

// Server Component (default in the Next.js App Router)
async function ProductList() {
  const products = await db.query("SELECT * FROM products");
  return (
    <ul>
      {products.map((p) => <li key={p.id}>{p.name}</li>)}
    </ul>
  );
}

To add interactivity (state, effects, event handlers), mark a component with the "use client" directive. A common pattern is a Server Component that fetches data and passes it as props to a small Client Component for the interactive parts.

What are Server Actions in React 19, and how are they used?

Server Actions are async functions marked with the "use server" directive. They always run on the server but can be called from the client — for example, passed straight to a form's action — letting you perform mutations without hand-writing an API route.

// actions.ts
"use server";

export async function createTodo(formData) {
  const title = formData.get("title");
  await db.todo.create({ data: { title } });
}

// component.tsx
import { createTodo } from "./actions";

function NewTodo() {
  return (
    <form action={createTodo}>
      <input name="title" />
      <button>Add</button>
    </form>
  );
}

Because the action runs on the server, the form works even before client JS loads (progressive enhancement). A Server Action is effectively a public endpoint — always validate and authorize its inputs inside the function; never trust them.

How does React 19 handle document metadata like <title> and <meta>?

React 19 natively supports rendering <title>, <meta>, and <link> tags anywhere in the component tree. React automatically hoists them into the document <head>, so libraries like react-helmet are no longer needed.

function BlogPost({ post }) {
  return (
    <article>
      <title>{post.title}</title>
      <meta name="description" content={post.excerpt} />
      <link rel="canonical" href={post.url} />
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </article>
  );
}

This works in Client and Server Components and during streaming SSR. Note that frameworks like Next.js still provide their own Metadata API, which is preferred there for deduping and ordering.

What resource-preloading APIs did React 19 add, and what do they do?

React 19 adds resource-hint APIs from react-dom: preload (fetch a resource like a font or stylesheet soon), preinit (fetch and eagerly execute/insert it), prefetchDNS (resolve a domain's DNS early), and preconnect (open a connection to an origin early).

import { preload, preinit, prefetchDNS, preconnect } from "react-dom";

function App() {
  preinit("https://example.com/script.js", { as: "script" });
  preload("https://example.com/font.woff2", { as: "font", crossOrigin: "anonymous" });
  preconnect("https://api.example.com");
  prefetchDNS("https://cdn.example.com");
  return <Main />;
}

React dedupes these hints and emits the corresponding <link> tags, improving load performance by starting network work earlier. They're safe to call during render.

What is the React Compiler, and how does it change how you optimize components?

The React Compiler is an opt-in, build-time tool (a Babel/SWC plugin) that automatically memoizes components and values. It largely removes the need to hand-write useMemo, useCallback, and React.memo just to avoid re-renders.

It relies on your code following the Rules of React (pure render, no mutation of props or state). It's independent of the React 19 runtime — you adopt it through your build config — but it's the recommended performance story for the React 19 era.

// babel.config.js
module.exports = {
  plugins: [["babel-plugin-react-compiler", {}]],
};

// With the compiler enabled, this needs no manual memoization:
function ProductList({ products, query }) {
  const filtered = products.filter((p) => p.name.includes(query));
  return filtered.map((p) => <Product key={p.id} product={p} />);
}