ESC

Search on this blog

Weekly updates

Join our newsletter!

Do not worry we don't spam!

React 19: New Hooks Explained


The world of web development is constantly evolving, with new libraries and technologies emerging regularly. React, one of the most widely used libraries, has recently announced a significant update with the release of React 19 beta version on April 25, 2024. This new version introduces a host of exciting features, including four new hooks that promise to revolutionize the way we handle forms and asynchronous operations. In this comprehensive article, we will delve into these new hooks, exploring their functionality and practical applications through detailed examples. 

 

I. Form Handling with New Hooks

Traditionally, form handling in React has involved managing state variables, handling submissions, and displaying pending states. However, the introduction of three new hooks in React 19 – useFormStatususeActionState, and useOptimistic – promises to streamline this process significantly.

 

1. useFormStatus Hook

The useFormStatus hook provides valuable information about the form's status during submission, eliminating the need for separate state variables to track pending states. This hook, imported from react-dom, returns an object containing two properties: pending (a boolean indicating whether the form is in a pending state) and data (an object of type FormData containing the values of the form fields). [1]

Here's an example of how to use the useFormStatus hook within a component:

 

import { useFormStatus } from 'react-dom';

const Form = () => {
  const { pending, data } = useFormStatus();

  return (
    <div>
      <input type="text" name="username" placeholder="Enter your name" />
      <button disabled={pending} type="submit">
        Submit
      </button>
      {pending && <p>Submitting {data?.get("username")}...</p>}
    </div>
  );
};

const FormStatusWithHooks = () => {
  return (
    <form
      action={async () => {
        await submitAction();
      }}
    >
      <Form />
    </form>
  );
};

In this example, the useFormStatus hook is used within the Form component to access the form's status and data. The pending state is used to disable the submit button during submission, and the data object is used to display the submitted form data. 

 

2. useActionState Hook

The useActionState hook simplifies the process of managing form state and handling submissions. It takes two parameters: submitData (a function called when the form is submitted) and initialState (the initial value of the state). The hook returns an array containing the current state and a new formAction function that can be passed to the action prop of the form element. 

Here's an example of how to use the useActionState hook:

import { useActionState } from 'react';
import { submitActionWithCurrentState } from '../../actions';

const ActionStateComponent = () => {
  const [state, formAction] = useActionState(submitActionWithCurrentState, {
    users: [],
    error: null,
  });

  return (
    <form action={formAction}>
      <div>
        <input type="text" name="username" placeholder="Enter your name" />
        <input type="number" name="age" placeholder="Enter age" />
        <button type="submit">Submit</button>
      </div>
      <div className="error">{state?.error}</div>
      {state?.users?.map((user) => (
        <div key={user.username}>
          Name: {user.username} Age: {user.age}
        </div>
      ))}
    </form>
  );
};

In this example, the useActionState hook is used to manage the state of a form that submits user information (name and age). The submitActionWithCurrentState function updates the state with the new user data or displays an error if a user with the same name already exists. The formAction function is passed to the action prop of the form element, and the component re-renders with the updated state after form submission. 

 

3. useOptimistic Hook

The useOptimistic hook allows you to optimistically update the UI while an asynchronous operation is still in progress. This hook takes two parameters: actualState (the value of the optimistic state when no action is pending) and updateFn (an optional function that calculates the optimistic state based on the actual state and the new value). It returns an array containing the optimistic state and a function to set the optimistic state. 

Here's an example of how to use the useOptimistic hook:

import { useOptimistic, useState } from 'react';
import { submitTitle } from '../../actions';

const OptimisticComponent = () => {
  const [title, setTitle] = useState('Title');
  const [optimisticTitle, setOptimisticTitle] = useOptimistic(title);
  const [error, setError] = useState(null);
  const pending = title !== optimisticTitle;

  const handleSubmit = async (formData) => {
    setError(null);
    setOptimisticTitle(formData.get('title'));
    try {
      const updatedTitle = await submitTitle(formData);
      setTitle(updatedTitle);
    } catch (e) {
      setError(e);
    }
  };

  return (
    <div>
      <h2>{optimisticTitle}</h2>
      <p>{pending && 'Updating...'}</p>
      <form action={handleSubmit}>
        <input type="text" name="title" placeholder="Change Title" />
        <button type="submit" disabled={pending}>
          Submit
        </button>
      </form>
      <div className="error">{error && error}</div>
    </div>
  );
};

In this example, the useOptimistic hook is used to optimistically update the page title while an asynchronous operation is in progress. The optimistic title is displayed immediately after form submission, and the actual title is updated once the asynchronous operation is complete. If the operation fails, the optimistic state reverts to the previous state, and an error message is displayed. 

 

II. useExisting Hook

While not a new hook, the use method introduced in React 19 provides a convenient way to read the value of a Promise or a Context inside a component. This method can be called inside components, hooks, and even conditional statements like if and for loops.

1. Reading Contexts with use

When working with contexts, the use method behaves similarly to the useContext hook, returning the value provided by the context for use within the component. 

import { createContext, use } from 'react';
import '../../styles.css';

const ThemeContext = createContext(null);

const UseHookWithContext = () => {
  return (
    <ThemeContext.Provider value="dark">
      <MyComponent />
    </ThemeContext.Provider>
  );
};

const MyComponent = () => {
  const theme = use(ThemeContext);
  return (
    <div className={`myContainer theme-${theme}`}>
      <h2>Hi There!</h2>
    </div>
  );
};

In this example, the use method is used to read the value of the ThemeContext within the MyComponent component. The retrieved value is then used to apply a CSS class based on the theme. 

 

2. Reading Resolved Values of Promises with use

The use method can also be used to read the resolved value of a Promise within a component. It integrates with the Suspense API to display a temporary message while the Promise is pending. 

"use client";

import { Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";

const DataContainer = ({ dataPromise }) => {
  return (
    <Suspense fallback={<p>Fetching Data...</p>}>
      <DataComponent dataPromise={dataPromise} />
    </Suspense>
  );
};

const DataComponent = ({ dataPromise }) => {
  const data = use(dataPromise);
  return <div>{data && data}</div>;
};

In this example, a Promise created in a server component is passed to the DataContainer component as dataPromise. The DataContainer component renders the DataComponent within a Suspense boundary, which displays a fallback message ("Fetching Data...") while the Promise is pending. 

Inside the DataComponent, the use method is called with the dataPromise, which returns the resolved value of the Promise. This value is then rendered within a div element. If the Promise rejects, the ErrorBoundary component (not shown) will catch the error and handle it appropriately. 

The use method simplifies the process of reading Promise values within components, eliminating the need for complex state management and conditional rendering based on the Promise's state. It provides a more declarative and straightforward approach to working with asynchronous data in React applications.

Samsung Galaxy Z Fold 6 Leak Reveals Surprising Omission of Key Feature
Prev Article
Samsung Galaxy Z Fold 6 Leak Reveals Surprising Omission of Key Feature
Next Article
9 Best Budget Smartphones of 2024: Affordable Phones with Top-Notch Features
9 Best Budget Smartphones of 2024: Affordable Phones with Top-Notch Features

Related to this topic: