DEV Community

Cover image for React 19 Features - Release Canary
Kevin Toshihiro Uehara
Kevin Toshihiro Uehara

Posted on

React 19 Features - Release Canary

Hi there, how have you been? Everything in peace? I hope so!
There was a long time that I don`t post anything here! But now I want to bring a lot of content of, what you guess?

YEAH! Let's talk about React 19 and the main features with examples and using Vite and Typescript!

I'm going to base on React 19 release notes documentation. But I will try to bring more easy examples.

So let's start the project using our React with Vite and Typescript. Enter on project directory and install the dependencies.

yarn create vite react-19rc-example --template react-ts

So with the project created, Vite will use the React 18 version. To change for React 19, we need to udpate (until the date of this post):

yarn add --exact react@rc react-dom@rc

And we need to add another dev dependencie, because we are using Typescript, on package.json:

`

{
  "dependencies": {
    "@types/react": "npm:types-react@rc",
    "@types/react-dom": "npm:types-react-dom@rc"
  },
  "overrides": {
    "@types/react": "npm:types-react@rc",
    "@types/react-dom": "npm:types-react-dom@rc"
  }
}
Enter fullscreen mode Exit fullscreen mode


`

And that's it! Now we upgraded to React 19 and we are prepared to code and see the examples:

React Compiler

Before of React 19, on the background the React use the Virtual DOM. So if any state change on any tree components, the React will compare the Virtual DOM with the Real DOM. But probably you alredy faced some problems of performance in your application.

Imagine that you have 4 childrens inside the father component. And the last child component changes. React will detect the state update, compare and change the entire tree of you components.

But we can use some approaches to avoid this problem of re-render, for example memoization. For example, use the:

  • useCallback
  • useMemo
  • memo

Now with the 19 release version, it was introduced the React Compiler So, now, the React render again when the semantic value changes, but without impact on the time cost and execution of deep comparations.

The React Compiler, introduced in React 19, is an advanced feature that aims to optimize the development experience and performance of React applications. Also known as the "Babel Inline JSX Transform", this compiler improves the way JSX is transformed into JavaScript. Here are the main points about React Compiler:

  • Direct Transformation of JSX
  • Elimination of the dead code
  • Otimizations for compilers
  • Three Shaking Improvements

The React Compiler replace the old method of JSX transformation to something more closer of native execution of Javascript.

Hooks Actions

React 19 bring the concept of some hooks called actions. I will bring the main and interesting new hooks:

  • useTransition
  • useActionState
  • useFormStatus
  • useOptimistic
  • useDeferredValue
  • use

useTransition

To understand, let's create a component and see the before and after to compare the use of the new hook:

`

// Before Actions
export const UpdateNameComponent = () => {
  const [name, setName] = useState("");
  const [error, setError] = useState(null);
  const [isPending, setIsPending] = useState(false);

  const handleSubmit = async () => {
    setIsPending(true);
    const error = await updateName(name);
    setIsPending(false);
    if (error) {
      setError(error);
      return;
    } 
  };

  return (
    <div>
      <input value={name} onChange={(event) => setName(event.target.value)} />
      <button onClick={handleSubmit} disabled={isPending}>
        Update
      </button>
      {error && <p>{error}</p>}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode


`

Now let's see now with React 19:

`

// Before Actions
export const UpdateNameComponent = () => {
  const [name, setName] = useState("");
  const [error, setError] = useState(null);
  const [isPending, startTransition] = useTransition();

 const handleSubmit = () => {
    startTransition(async () => {
      const error = await updateName(name);
      if (error) {
        setError(error);
        return;
      }

      console.log("SUCCESS");
    });
  };

  return (
    <div>
      <input value={name} onChange={(event) => setName(event.target.value)} />
      <button onClick={handleSubmit} disabled={isPending}>
        Update
      </button>
      {error && <p>{error}</p>}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode


`

useActionState

The hook useActionState was introduced and projected to simplify the async operations on forms and another integrations that envolves state management and side effects.

The useActionState receive two parameters:

  • Async function that will return a new payload whith the new state of the promisse.
  • Initial State of the component before for any action to be executed.

`

import { useActionState } from "react";

const submitAction = async (prevState, formData) => {
  const response = await updateName(formData);
  return { ...prevState, data: response.data, status: response.success ? "SUCCESS" : "ERROR" };
};

const initialState = { data: null, status: "INIT" };

const FormComponent = () => {
  const [state, submit, isPending] = useActionState(submitAction, initialState);

  return (
    <form action={submit}>
      <input type="text" name="input" placeholder="Type something" />
      <button type="submit" disabled={isPending}>Submit</button>
      <div>
        {state.status === "INIT" && <p>Awaiting submission...</p>}
        {state.status === "SUCCESS" && <p>Submission successful!</p>}
        {state.status === "ERROR" && <p>Submission failed. Try again.</p>}
      </div>
    </form>
  );
};
Enter fullscreen mode Exit fullscreen mode


`

useFormStatus

The useFormStatus is one of the <form/> integrations. It was introduced to form state management, specially on async operations and validations. We can say, that is a generic form to validate form, like react-forms.

`

import { useFormStatus } from "react";

const FormComponent = () => {
  const { isSubmitting, isValidating, isSuccessful, hasError } = useFormStatus();

  return (
    <form>
      <input type="text" name="name" placeholder="Name" />
      <button type="submit" disabled={isSubmitting || isValidating}>Submit</button>

      {isSubmitting && <p>Submitting...</p>}
      {isValidating && <p>Validating...</p>}
      {isSuccessful && <p>Form submitted successfully!</p>}
      {hasError && <p>Error occurred during submission.</p>}
    </form>
  );
};
Enter fullscreen mode Exit fullscreen mode


`

Amazing, right?

useOptimistic

The useOptimistic allows the temporary update of the state, assuming that the operation was successfully or not.

This hook receive two parameters:

  • actualState: the real actual state that the hook should use as base.
  • updateFn (optional): this function will return the real state with the value received (setOptimisticState), calculating the new state optimistic.

`

import { useOptimistic } from "react";

const fakeApiCall = (newTitle) => new Promise((resolve, reject) => {
  setTimeout(() => {
    Math.random() > 0.5 ? resolve() : reject();
  }, 1000);
});

const TitleComponent = () => {
  const [title, setTitle] = useState("Old Title");
  const [optimisticTitle, setOptimisticTitle] = useOptimistic(title);
  const [error, setError] = useState(null);

  const handleUpdateTitle = async (newTitle) => {
    setError(null);
    setOptimisticTitle(newTitle);

    try {
      await fakeApiCall(newTitle);
      setTitle(newTitle);
    } catch (e) {
      setOptimisticTitle(title);
      setError("Failed to update title");
    }
  };

  return (
    <div>
      <h1>{optimisticTitle}</h1>
      {error && <p>{error}</p>}
      <button onClick={() => handleUpdateTitle("New Title")}>
        Update Title
      </button>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode


`

useDeferredValue

On the new version of React 19, was introced the initialValue option to useDeferredValue.

When initialValue is provided, the useDeferredValue will return it as value for the initial render of the component, and schedules a re-render in the background with the deferredValue returned.

`

import { useDeferredValue } from "react";

const Search({deferredValue}: {deferredValue: string}) {
  // On initial render the value is ''.
  // Then a re-render is scheduled with the deferredValue.
  const value = useDeferredValue(deferredValue, '');

  return (
    <Results query={value} />
  );
}
Enter fullscreen mode Exit fullscreen mode


`

use

ANNND the use. Probably one of the amazing hooks. Just "use"! I'm kidding!

But now the side effects that you already faced using the useEffect. Now you can read a primise with use and the React will Suspend until the promise resolves.

`

import {use} from 'react';

const Comments = ({commentsPromise}) => {
  const comments = use(commentsPromise);
  return comments.map(comment => <p key={comment.id}>{comment}</p>);
}

const Page = ({commentsPromise}: {commentsPromise: Promise<any>}) => {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Comments commentsPromise={commentsPromise} />
    </Suspense>
  )
}
Enter fullscreen mode Exit fullscreen mode


`

So, until the promise resolve, react will render the Suspense as fallback component. Incredible, right???

REF as a prop

Now in new version of React 19, now we can access ref as a prop for function components. Now will no longer need forwardRef (OMG!!! Emotional)

`

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

<MyInput ref={ref} />
Enter fullscreen mode Exit fullscreen mode


`

Support for Document Metadata!!!

Now we can use the metadata on our components!!! It is a BIG step for SEO improvements!!!
In the past, tags like "

", "" and "" were reserved for placement in the "" section of the document. Now with the new version, React support for renderding document metadata tags in component natively. When React, render the component, it will see the "", "" and "" tags, and automatically hoist them to the section of document.

`

const BlogPost = ({post}) => {
  return (
    <article>
      <h1>{post.title}</h1>
      <title>{post.title}</title>
      <meta name="author" content="Josh" />
      <link rel="author" href="https://twitter.com/joshcstory/" />
      <meta name="keywords" content={post.keywords} />
      <p>
        Eee equals em-see-squared...
      </p>
    </article>
  );
}


`

Support for Stylesheets

Stylesheets, both externally linked () and inline (...), require careful positioning in the DOM due to style precedence rules. Building a stylesheet capability that allows for composability within components is hard, so users often end up either loading all of their styles far from the components that may depend on them, or they use a style library which encapsulates this complexity.

Now in React 19, we can use this complexity and provide the styles in our own component, using integration into concourrent rendering.

If you tell React the precedence of your stylesheet it will manage the insertion order of the stylesheet in the DOM and ensure that the stylesheet (if external) is loaded before revealing content that depends on those style rules.

`

function ComponentOne = () => {
  return (
    <Suspense fallback="loading...">
      <link rel="stylesheet" href="foo" precedence="default" />
      <link rel="stylesheet" href="bar" precedence="high" />
      <article class="foo-class bar-class">
        {...}
      </article>
    </Suspense>
  )
}

const ComponentTwo = () => {
  return (
    <div>
      <p>{...}</p>
      <link rel="stylesheet" href="baz" precedence="default" />  <-- will be inserted between foo & bar
    </div>
  )
}


`

And that's it folks!
There's a lot more features of React 19, like Server Components and Server Actions that was added. But these themes I want to introduce you in another article.

The main objective of this article was to bring the main news about React 19.

I hope you liked it!
Thank you so much and stay well always!

The Office Thank you

Contacts:
Linkedin: https://www.linkedin.com/in/kevin-uehara/
Instagram: https://www.instagram.com/uehara_kevin/
Twitter: https://twitter.com/ueharaDev
Github: https://github.com/kevinuehara
dev.to: https://dev.to/kevin-uehara
Youtube: https://www.youtube.com/@ueharakevin/

Top comments (2)

Collapse
 
anmolbaranwal profile image
Anmol Baranwal

very detailed :)

Will give it a complete read later. Hooks seem interesting, but there are extensive hooks libraries that are already available. What do you think?

Collapse
 
kevin-uehara profile image
Kevin Toshihiro Uehara

Hi Anmon! Thank you so much and I hope you like it!
As you said there's a lot libraries more robusts that I love to work. Example: React Query, Jotai, Astro and a lot of more...
I think these libraries will not be replaced, I think the new version of React just want to turn easier and bring the new hooks and React Compiler, just to help and make the developer experience (DevX). Who knows, if the React on the next releases want to nativaly bring features that already exists? Just to wait what direction the React Community want to follow.

But Answer you question, I wouldn't exchange these technologies even for the new features of react 19. Because they are already very mature with lots of features