umma.dev

React 19

Watch this space ☺️

Edit 27th April: React 19 is in Beta! Check out this post to read more.

Actions and Forms

Support for async functions when handling the following transitions:

Pending States

Starts at the beginning of a request and automatically resets when final state update is committed

Errors

Display Error Boundaries when a request fails and revert optimistic updates to original value

Forms

<form> elements now support functions to action and formAction

Optimistic Updates

Support for the new useOptimistic hook to show feedback whilst request are being submitted

…automatically.

function ChangeName({ name, setName }) {
  const [error, submitAction, isPending] = useActionState(
    async (previousState, formData) => {
      const error = await updateName(formData.get("name"));
      if (error) {
        return error;
      }
      redirect("/path");
    }
  );

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

use Hook

Read resources in render. Read a promise and React will suspend until the promise resolves.

import { use } from "react";

function Comments({ commentsPromise }) {
  // `use` will suspend until the promise resolves.
  const comments = use(commentsPromise);
  return comments.map((comment) => <p key={comment.id}>{comment}</p>);
}

function Page({ commentsPromise }) {
  // When `use` suspends in Comments,
  // this Suspense boundary will be shown.
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Comments commentsPromise={commentsPromise} />
    </Suspense>
  );
}

You cannot use use when promises are created in render, due to client components.

Another use case for use is to read Context conditionally.

import { use } from "react";
import ThemeContext from "./ThemeContext";

function Heading({ children }) {
  if (children == null) {
    return null;
  }

  // This would not work with useContext
  // because of the early return.
  const theme = use(ThemeContext);
  return <h1 style={{ color: theme.color }}>{children}</h1>;
}

<Context>

No more <Context.Provider> needed.

const ThemeContext = createContext("");

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

React Server Components

This has already been implemented in Next.js (like many of the other features described within this post).

If you have used PHP in the past this may make more sense; putting data on the server and only rendering what’s needed and when it’s needed.

Server Actions

Server actions allow client components to call async functions on the server via use server. `

The only caveat to using them in React 19 is the following:

While React Server Components in React 19 are stable and will not break between major versions, the underlying APIs used to implement a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x.

To support React Server Components as a bundler or framework, we recommend pinning to a specific React version, or using the Canary release. We will continue working with bundlers and frameworks to stabilize the APIs used to implement React Server Components in the future.

There is a lot of information flying around about React Server Components, so I’m not going to even try to summarise it here.

ref

No longer need forwardRef.

function MyInput({ placeholder, ref }) {
  return <input placeholder={placeholder} ref={ref} />;
}

//...
<MyInput ref={ref} />;

Hydration Errors

They’ve finally updated the errors to be more readable! 🎉

Uncaught Error: Hydration failed because the server rendered HTML didn’t match the client. As a result this tree will be regenerated on the client. This can happen if an SSR-ed Client Component used:

- A server/client branch if (typeof window !== 'undefined').
- Variable input such as Date.now() or Math.random() which changes each time it’s called.
- Date formatting in a user’s locale which doesn’t match the server.
- External changing data without sending a snapshot of it along with the HTML.
- Invalid HTML tag nesting.

It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.

https://react.dev/link/hydration-mismatch

  <App>
    <span>
+    Client
-    Server

  at throwOnHydrationMismatch

Other

Having heard (unofficially) about React Compiler and memo, and it not being included in this post, I’m intrigued as to what will happen with it.