React 19: The long-expected features
Tags: react, react19, compiler, use
Published: 2024-04-17 03:52:32

React 19 introduces a number of new features that will undoubtedly make the life of react developers simpler. While the release is not yet stable, you can test out the new features using the canary version.

```console
npm i react@canary react-dom@canary
```

## React Forget

The react compiler (called "React Forget") in version <InlineCode>19</InlineCode> is nothing short of game-changing. Whiles some solutions included their own compilers to maximize developer efficiency, React initially solely operated in the browser. 


Once a compiler is in place, React developers can concentrate on creating business features rather than worrying about things like momoization. 
Yes, you heard that righ the momoization hooks (<InlineCode>useMemo</InlineCode> and <InlineCode>useCallback</InlineCode>) and <InlineCode>memo</InlineCode> API will no longer be needed since
the compiler will be handling that automatically and more efficiently without compromising the application performance nor the code base quality.

The React compiler is already been deployed in Instagram web app Production. You can see it in action in this [ReactAdvanced Conf talk](https://www.youtube.com/watch?v=qOQClO3g8-Y) by Joe Savona and Mofei Zhang.

## Actions

React 19 introduces the ability to run actions on either the server or the client using the directives <InlineCode>"use client"</InlineCode> 
or <InlineCode>"use server"</InlineCode>. Previously, Server Actions were used to transport data from the client to the server. 
As a result, we now refer to them as "actions". 

If you're acquainted with [NextJs](https://nextjs.org/), the directives will come as no surprise.

To manage async actions, React provides a <InlineCode>useFormStatus</InlineCode> and <InlineCode>useFormState</InlineCode> hooks to handle the pending status and state to prevent multiple submissions of a form for instance.

## Hooks

React 19 came with a set of new hooks that will either replace existing hooks or support the new of its features.

### useFormStatus

```jsx
import { useFormStatus } from "react-dom";
import action from './actions';

function Submit() {
  const {pending} = useFormStatus(); // will return {pending, data, method, action}
  return <button disabled={pending}>Submit</button>
}

export default function App() {
  return (
    <form action={action}>
      <Submit />
    </form>
  );
}
```

### useFormState

The actions can also return values, in that case we need use the <InlineCode>useFormState</InlineCode> hook.

```jsx
import { useFormState } from "react-dom";

async function increment(previousState, formData) {
  return previousState + 1;
}

function StatefulForm({}) {
  const [state, formAction] = useFormState(increment, 0);
  return (
    <form>
      {state}
      <button formAction={formAction}>Increment</button>
    </form>
  )
}
```

Know more about the [useFormStatus](https://react.dev/reference/react-dom/hooks/useFormStatus) and [useFormState](https://react.dev/reference/react-dom/hooks/useFormState) hooks.

### useOptimistic

The useOptimistic hook can be used to provide the user with a temporary ui based on what they already submitted, 
for instance showing the newly sent message while the data is processed on the server.

```jsx
import { useOptimistic, useState, useRef } from "react";
import { deliverMessage } from "./actions.js";

function Thread({ messages, sendMessage }) {
  const formRef = useRef();
  async function formAction(formData) {
    addOptimisticMessage(formData.get("message")); // we get the input of the user; used to build the temp ui.
    formRef.current.reset(); // reset the form.
    await sendMessage(formData); // sending the data to the server asynchronosly.
  }
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(
    messages,
    (state, newMessage) => [
      ...state,
      {
        text: newMessage,
        sending: true
      }
    ]
  );

  return (
    <>
      {optimisticMessages.map((message, index) => ( // getting the newly sent messages, mapping them into dom elements (optimistic UI).
        <div key={index}>
          {message.text}
          {!!message.sending && <small> (Sending...)</small>}
        </div>
      ))}
      <form action={formAction} ref={formRef}> {/* Just a simple form with action and ref*/}
        <input type="text" name="message" placeholder="Hello!" />
        <button type="submit">Send</button>
      </form>
    </>
  );
}

// Putting the Thread component in action by providing a state.
export default function App() {
  const [messages, setMessages] = useState([
    { text: "Hello there!", sending: false, key: 1 }
  ]);
  async function sendMessage(formData) {
    const sentMessage = await deliverMessage(formData.get("message"));
    setMessages((messages) => [...messages, { text: sentMessage }]);
  }
  return <Thread messages={messages} sendMessage={sendMessage} />;
}
```
Know more about the [useOptimistic](https://react.dev/reference/react/useOptimistic) hook.

### useCallback and useMemo

As previously stated the momoization will be handled by the React Compiler, therefor the <InlineCode>useMemo</InlineCode>, 
<InlineCode>useCallback</InlineCode> hooks and <InlineCode>memo</InlineCode> API won't make it to the version 19 of React.

### use

The use hook is here to clean more the react code base, it will replace two widly used hooks (thank God): <InlineCode>useEffect</InlineCode> and <InlineCode>useContext</InlineCode>.

One of the famous use cases for the <InlineCode>useEffect</InlineCode> hook is data fetching, for this example we fetch the user details and return a UserProfile:

```jsx

  // Using useEffect hook to fetch data.
  export const UserProfile = () => {
    const [userDetails, setUserDetails] = useState(null);

    useEffect(()=>{
      getUserDetails() // async function
        .then(data => {
          setUserDetails(data);
        })
        .catch(error => console.log(error))
    },[])

    if (!userDetails) return <p>Loading...</p>

    return (
      <p>{userDetails.name}</p>
    )

  }

  // Using use hook to fetch data.
  export const UserDetails = () => {  // another component for simplicity
    const userDetails = use(getUserDetails());
    return (
       <p>{userDetails.name}</p>
    )
  }

  export const UserProfile = () => {
    return (
      <Suspense fallback={<p>Loading...</p>}>
      <p>{userDetails.name}</p>
      </Suspense>
    )
  }
```

The <InlineCode>use</InlineCode> hook will also be replacing the <InlineCode>useContext</InlineCode> hook:

```jsx

// Using useContext hook to consume the theme context.
const theme = useContext(ThemeContext);

// Using use hook to consume the theme context
const theme = use(ThemeContext);

```


## ForwardRef

No more forwardRef! We can simply pass the ref down like any other prop without the use of forwardRef.

```jsx
// Before
export const ProfilePicture = forwardRef(
  (props, ref) => ( // src and alt are props
    <img ref={ref} {...props}/>
  )
)

// On v19
export const ProfilePicture = (ref, ...props) => {
  <img ref={ref} {...props}/>
}
```

## SEO

React will enable the usage of the <InlineCode>\<title\></InlineCode>, <InlineCode>\<meta\></InlineCode>, and <InlineCode>\<link\></InlineCode> tags anywhere in the App, improving SEO performance. 
Previously, libraries like as [react-helmet](https://www.npmjs.com/package/react-helmet) were used for this.

## Summary

In my perspective, React v19 will deliver a lot of relevant and required enhancements, allowing developers to focus more on important features that matter!

# Resources
https://react.dev/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024#react-compiler
https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-optimizing-compiler
https://www.youtube.com/watch?v=qOQClO3g8-Y
https://react.dev/reference/react/