DevAcademy
LearnReactReact 19 Features
AdvancedReact

React 19 Features

An overview of newer React APIs — Actions, the use() hook, and simplified form handling.

Reading Time

16 min

Lesson

Lesson 40 of 42

The use() Hook

use() reads the value of a resource — like a Promise or a Context — and can be called conditionally, unlike other hooks. When passed a Promise, it suspends the component until the Promise resolves, integrating naturally with Suspense.

Reading a Promise with use()

import { use, Suspense } from "react";

function UserProfile({ userPromise }) {
  const user = use(userPromise); // suspends until resolved
  return <h1>{user.name}</h1>;
}

function App({ userPromise }) {
  return (
    <Suspense fallback={<p>Loading...</p>}>
      <UserProfile userPromise={userPromise} />
    </Suspense>
  );
}

Actions

An Action is an async function passed to a form’s action prop (or used with useTransition), which React handles automatically — managing pending state, errors, and optimistic updates without manually wiring up useState for each of those concerns.

A Form Using an Action

function UpdateNameForm() {
  async function updateName(formData) {
    const name = formData.get("name");
    await saveName(name);
  }

  return (
    <form action={updateName}>
      <input type="text" name="name" />
      <button type="submit">Save</button>
    </form>
  );
}

useActionState

useActionState wraps an Action and gives you back its current state (like a success message or validation error) along with a pending flag, without manually tracking either with separate useState calls.

useActionState Example

import { useActionState } from "react";

function ChangeNameForm() {
  const [error, submitAction, isPending] = useActionState(
    async (previousState, formData) => {
      const name = formData.get("name");
      if (!name) return "Name is required";
      await saveName(name);
      return null;
    },
    null
  );

  return (
    <form action={submitAction}>
      <input type="text" name="name" />
      <button disabled={isPending}>Save</button>
      {error && <p>{error}</p>}
    </form>
  );
}

useOptimistic

useOptimistic lets the UI show an expected result immediately, before an async Action actually finishes — automatically reverting if the action fails, giving a snappier feel for actions like liking a post or sending a message.

Optimistic UI Update

import { useOptimistic } from "react";

function LikeButton({ likes, onLike }) {
  const [optimisticLikes, addOptimisticLike] = useOptimistic(
    likes,
    (state) => state + 1
  );

  async function handleLike() {
    addOptimisticLike();
    await onLike(); // if this fails, optimisticLikes reverts automatically
  }

  return <button onClick={handleLike}>❤️ {optimisticLikes}</button>;
}

The ref Prop No Longer Needs forwardRef

As of React 19, function components can accept ref directly as a regular prop, removing the need for forwardRef() in most cases where a component just needs to expose an underlying DOM node.

Best Practice

Reach for Actions and useActionState for form submissions instead of manually wiring useState for pending/error/success — they cover the most common form-handling boilerplate with far less code.

Interview Questions

Quick Quiz

1. What is unique about the use() hook compared to other hooks?

2. What does useActionState provide beyond a plain async function?

3. What does useOptimistic do?