React 19 Features - Release Canary
Tags: react, javascript, typescript, braziliandevs
Published: 2024-06-27 13:49:55

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:


````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"
  }
}
````

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:

````tsx
// 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>
  );
}
````

Now let's see now with React 19:

````tsx
// 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>
  );
}
````

### 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.

````tsx
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>
  );
};
````

### 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.

````tsx
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>
  );
};
````

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.

````tsx
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>
  );
};
````
### 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.

````tsx 
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} />
  );
}
````

### 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.

````tsx
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>
  )
}
````

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)

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

<MyInput ref={ref} />
````

### 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 "<title>", "<link>" and "<meta>" were reserved for placement in the "<head>" 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 "<title>", "<link>" and "<meta>" tags, and automatically hoist them to the <head> section of document. 

````tsx
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 (<link rel="stylesheet" href="...">) and inline (<style>...</style>), 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.

````tsx
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tdsjf0awsyr3f6wuidpg.gif)


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/