A Deep Dive Into Hooks In React 18
Published: 2024-06-08 16:37:34


by [Chidi Confidence](https://blog.openreplay.com/authors/chidi-confidence)




<blockquote><em>
In the dynamic realm of web development, React 18 emerges as a beacon of innovation, introducing a plethora of features designed to empower developers and enhance the user experience. Among the noteworthy additions are four powerful hooks: `useTransition`, `useMutableSource`, `useDeferredValue`, and `useSyncExternalStore`. This comprehensive exploration delves into the intricacies of each hook, providing developers with a profound understanding of their functionality and usage.
</em></blockquote>





<div style="background-color:#efefef; border-radius:8px; padding:10px; display:block;">
<hr/>
<h3><em>Session Replay for Developers</em></h3> 
<p><em>Uncover frustrations, understand bugs and fix slowdowns like never before with <strong><a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a></strong> — an open-source session replay suite for developers. It can be <strong>self-hosted</strong> in minutes, giving you complete control over your customer data.</em></p>
<img alt="OpenReplay" style="margin-top:5px; margin-bottom:5px;" width="768" height="400" src="https://raw.githubusercontent.com/openreplay/openreplay/main/static/openreplay-git-hero.svg" class="astro-UXNKDZ4E" loading="lazy" decoding="async">
<p><em>Happy debugging! <a href="https://openreplay.com" target="_blank">Try using OpenReplay today.</a></em><p>
<hr/>
</div>




[React's Version 18](https://legacy.reactjs.org/blog/2022/03/29/react-v18.html) represents a significant evolution in the React ecosystem, bringing forth improvements in performance, rendering, and state management. It introduces features that simplify development workflows and pave the way for novel approaches to building user interfaces. The release focuses on equipping developers with tools to create more responsive, efficient, and dynamic web applications. 

### Benefits of Version 18 Hooks

Explore the following unique benefits for elevated development experiences:

* [`useTransition`](https://legacy.reactjs.org/docs/hooks-reference.html#usetransition): Enhances the creation of smooth and responsive user interfaces by facilitating graceful transitions between different states. This hook offers developers control over when should commit the transition, empowering them to prioritize rendering or user interactions based on their specific needs.
* [`useMutableSource`](https://github.com/reactjs/rfcs/blob/main/text/0147-use-mutable-source.md): Facilitates seamless integration with external data sources, empowering to interact with mutable data without triggering unnecessary re-renders. This is particularly valuable in scenarios where the data source can be mutated without necessitating a complete re-render of the component tree.
* [`useDeferredValue`](https://legacy.reactjs.org/docs/hooks-reference.html#usedeferredvalue): Optimizes performance by deferring certain updates until the browser is idle. It is beneficial in scenarios where specific updates are not time-sensitive, allowing them to be delayed to enhance the overall user experience.
* [`useSyncExternalStore`](https://legacy.reactjs.org/docs/hooks-reference.html#usesyncexternalstore): Streamlines synchronization between React state and external state management systems. It proves valuable in scenarios where external stores, such as [React-Redux](https://react-redux.js.org/) or [MobX](https://mobx.js.org/react-integration.html), require alignment with internal state for seamless coordination.

## `useTransition`

The `useTransition` hook is a relatively new addition to the collection of hooks introduced in version 18. It is designed to manage complex UI transitions by allowing you to defer the rendering of certain components. Doing so helps prevent performance bottlenecks and improves the user experience during intense updates or transitions.

The primary goal of `useTransition` is to enable applications to stay responsive and maintain smooth animations even during heavy operations, such as data fetching, large-scale updates, or any process that might cause the UI to freeze temporarily.

Follow these steps to start using `useTransition` in your react application:

* [Update to version 18 (or higher)](https://legacy.reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html): Before using the `useTransition` hook, ensure that your application is running on version 18 or higher. This hook was introduced in React 18, so you need to update your project’s dependencies accordingly.
* Import the hook: To use the `useTransition` hook, import it from the package.

```javascript
import { useTransition } from 'react';
```

* Define the Transition: Next, define the transition using the `useTransition` hook. The hook requires two arguments: the resource-intensive function and a configuration object.

```javascript
const [startTransition, isPending] = useTransition();
```

Example.

```javascript
import { useState, useTransition } from "react";

export default function App() {
  const [data, setData] = useState([]);
  const [isPending, startTransition] = useTransition({ timeoutMs: 3000 });

  const fetchData = async () => {
    startTransition(() => {
      setData([]);
    });

    try {
      const response = await fetch(
        "https://jsonplaceholder.typicode.com/todos"
      );
      const data = await response.json();
      startTransition(() => {
        setData(data);
      });
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <div>
      <button onClick={fetchData}> Fetch Data </button>
      {isPending ? (
        <p> Loading... </p>
      ) : (
        <ul>
          {data.map((item) => (
            <li key={item.id}>{item.title}</li>
          ))}
        </ul>
      )}
    </div>
  );
}
```

In this example, we leverage the power of the `useTransition` hook in a component to orchestrate a smooth and responsive transition between different states while fetching data from an external API. The primary goal is to enhance the user experience by providing feedback during the asynchronous operation and ensuring a seamless transition between loading and displaying the fetched data. When the user clicks the "Fetch Data" button, the `fetchData` function is triggered. Inside this function, we initiate the first transition using `startTransition`. During this transition, the `setData` function is called to update the `data` state to an empty array, and the `isPending` state is set to `true`. As a result, a loading indicator is displayed, signaling to the user that data is being fetched. Simultaneously, the actual asynchronous API call is made using the `fetch` function. Upon successful retrieval of the API response, a second transition is triggered. This time, the `setData` function updates the `data` state with the fetched data, and the `isPending` state is set to `false`. Consequently, the loading indicator disappears, and the fetched data is rendered in the component.

It's important to note that the use of `useTransition` helps optimize the user interface by managing the timing and sequencing of state transitions. The provided `timeoutMs` option specifies a maximum duration for the transition, ensuring that the user interface remains responsive even if the API call takes some time to complete. Overall, this approach contributes to a more performant and user-friendly application. [Run code](https://codesandbox.io/p/sandbox/snowy-frog-ggrtpp)

Output.

![chrome_5gEP94EcYE](https://blog.openreplay.com/images/a-deep-dive-into-hooks-in-react-18/images/image1.gif)

## `useMutableSource`

The `useMutableSource` hook enhances the integration of external data sources or libraries within React's rendering pipeline by efficiently managing mutable data sources. This results in improved performance and facilitates smoother updates to components.

Example.

```javascript
import { useMutableSource } from 'react';

function App() {
  const mutableSource = getMutableSource(); // Get the mutable source from an external library
  const data = useMutableSource(mutableSource, getData, subscribe);

  return <div>{data}</div>;
}
```

In this illustration, the `getMutableSource()` function is employed to acquire the mutable source from an external library. The `getData` function fetches data from this mutable source, while the `subscribe` function registers a callback to receive data updates. The `useMutableSource` hook adeptly handles the subscription process and ensures that the data variable is promptly updated whenever changes transpire in the mutable source.


<CTA_Middle_Frameworks />



## `useDeferredValue`

The `useDeferredValue` hook allows developers to defer the processing of expensive computations until later. This can help improve your application's performance by reducing the amount of work that needs to be done during each render cycle.

Example.

```javascript
import { useState, useEffect, useDeferredValue } from "react";

const AsyncOperation = () => {
  const [data, setData] = useState([]);
  const [page, setPage] = useState(1);

  const deferredPage = useDeferredValue(page, { timeoutMs: 1000 });

  const fetchData = async () => {
    try {
      const response = await fetch(
        `https://jsonplaceholder.typicode.com/photos?_page=${deferredPage}`
      );

      const newData = await response.json();
      setData((prevData) => [...prevData, ...newData]);
    } catch (error) {
      console.error(error);
    }
  };

  useEffect(() => {
    fetchData();
  }, [deferredPage]);

  const handleLoadMore = () => {
    setPage((prevPage) => prevPage + 1);
  };

  return (
    <div>
      <button onClick={handleLoadMore}> Load More </button>
      <ul>
        {data.map((item) => (
          <li key={item.id}>
            <img src={item.thumbnailUrl} alt={item.title} width={20} />
          </li>
        ))}
      </ul>
    </div>
  );
};

export default AsyncOperation;
```

Output. 

![chrome_q80dOu9VsA](https://blog.openreplay.com/images/a-deep-dive-into-hooks-in-react-18/images/image2.gif)

In this example, the `AsyncOperation` component utilizes the `useDeferredValue` hook to optimize the rendering and performance of an asynchronous data fetching operation. The primary goal is to defer the update of the `page` state by one second when the user interacts with the "Load More" button. This delay, facilitated by the `useDeferredValue` hook, optimizes the rendering process and prevents unnecessary re-renders triggered by rapid state changes. Let's break down the key aspects of the code.

Defer State with `useDeferredValue`.

```javascript
const deferredPage = useDeferredValue(page, { timeoutMs: 1000 });
```
The `useDeferredValue` hook creates a deferred version of the `page` state. This means that when the user clicks the "Load More" button, the immediate update of the `page` state is delayed by one second. During this delay, the `deferredPage` variable reflects the current state of the `page` but with a one-second lag.

Fetch Data Function.

```javascript
const fetchData = async () => {
  try {
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/photos?_page=${deferredPage}`
    );

    const newData = await response.json();
    setData((prevData) => [...prevData, ...newData]);
  } catch (error) {
    console.error(error);
  }
};
```

The `fetchData` function makes an asynchronous API call to fetch data based on the current `deferredPage`. This function is invoked within the `useEffect` hook, ensuring it runs whenever the deferred page changes.

`useEffect` Hook for Fetching Data.

```javascript
useEffect(() => {
  fetchData();
}, [deferredPage]);
```

The `useEffect` hook is set up to execute the `fetchData` function whenever the `deferredPage` changes. Since the `deferredPage` value lags behind the actual `page` state by one second, React has a brief period to optimize rendering and avoid unnecessary updates triggered by frequent state changes.

Load More Button Handler.

```javascript
const handleLoadMore = () => {
  setPage((prevPage) => prevPage + 1);
};
```

The "Load More" button click event triggers the `handleLoadMore` function, which increments the `page` state. Due to the deferred nature of `deferredPage`, React introduces a one-second delay before updating `deferredPage` to the new page value.

The utilization of the `useDeferredValue` hook in this code exemplifies a strategy to enhance the performance of components, particularly in scenarios involving user interactions leading to frequent state updates. The one-second delay introduced by `useDeferredValue` allows for strategic management rendering and ensures a more efficient handling of asynchronous data fetching operations. [Run code ](https://codesandbox.io/p/sandbox/reverent-parm-zln3zz)

## `useSyncExternalStore`

The `useSyncExternalStore` hook empowers developers to harmonize a component's state with an external store. This functionality is valuable in crafting sophisticated applications that amalgamate data from diverse sources.

```javascript
import { useState, useEffect } from 'react';
import { useSyncExternalStore } from 'react';

const MyComponent = () => {
  const [count, setCount] = useState(0);
  const syncExternalStore = useSyncExternalStore();

  useEffect(() => {
    // fetch the initial count from an external API
    fetch('https://example.com/count')
      .then(response => response.json())
      .then(data => setCount(data.count))
      .catch(error => console.error(error));
  }, []);

  useEffect(() => {
    // sync the count value with the external store
    syncExternalStore('count', count);
  }, [count, syncExternalStore]);

  const incrementCount = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <div> Count: {count} </div>
      <button onClick={incrementCount}> Increment Count </button>
    </div>
  );
};
```

In this illustrative example, we employ the `useSyncExternalStore` hook to ensure synchronization of a count value with an external data store. To begin, we establish a `count` state variable via the `useState` hook, initializing it to 0. Subsequently, we employ the `useEffect` hook to retrieve the initial count value from an external API, updating the `count` state variable through the `setCount` method. We utilize another `useEffect` hook to synchronize the `count` value with the external store, employing the `syncExternalStore` method. This method requires two arguments: a key value identifying the data to be synchronized (here, `'count'`) and the current value of the data. Lastly, we define a`incrementCount` function responsible for incrementing the `count` state variable by 1. We then render a button that invokes this function upon clicking.

By leveraging `useSyncExternalStore`, we maintain coherence between our application state and external data stores, such as databases or caching systems. This proves particularly beneficial in the development of real-time applications or collaborative platforms requiring shared state across multiple devices or users.

## Conclusion

In summary, version 18 of React introduces a diverse range of new hooks, empowering developers to construct applications that are not only more efficient but also more accessible. By harnessing these innovative hooks, developers can craft applications with enhanced flexibility and performance, all while minimizing the necessity for redundant boilerplate code. These hooks constitute a valuable enhancement to the library, destined to become indispensable tools for developers immersed in React development.