UseTransition() Vs UseDeferredValue() In React 18
Tags: javascript, webdev, react
Published: 2022-05-20 21:22:57

by [Daniel Ita](https://blog.openreplay.com/authors/daniel-ita)


React 18 has introduced a key new concept known as "concurrency". Concurrency involves the simultaneous execution of multiple state updates, which is arguably the most important feature in React 18. Along with concurrency, there are two new hooks introduced by React 18 known as the UseTransition() and the UseDeferredValue() hook. They both help with de-prioritizing state updates, but the question is, when should they be used? 

For this article, you should have Node.Js and React 18 installed in your system. You can check out how to install React 18 in this video [here](https://www.youtube.com/watch?v=3IHnx03FPgE).


## What is Concurrent React?

According to the [Official React18 Docs](https://reactjs.org/blog/2022/03/29/react-v18.html), concurrent React is

> a new behind-the-scenes mechanism that enables React to prepare multiple versions of your UI simultaneously. You can think of concurrency as an implementation detail — it's valuable because of its features. 

Concurrency can be defined as the ability to do numerous tasks at the same time. Concurrency isn't precisely a feature; instead, it's a behind-the-scenes function that allows React to prepare many instances of your UI simultaneously (concurrently). React creates APIs in a way that hides implementation specifics from developers. React creators believe that React developers should concentrate on how React features will help them accomplish the user experience they desire for their clients, and that React will figure out how to deliver that experience.

Concurrent React is more than just an implementation detail. Rather, it is a significant upgrade that updates the framework's core rendering architecture. Thus, it's essential to understand how it works in React 18.


## Setting up the project

For this article, I have created a Github repo in which I built a simple demo product app that allows a user to view a product by inputting the product number. To get started, you have to clone the Github repo, which contains all the project starter files. To clone the Github repo, go to your terminal and run the  following command:

```
git clone https://github.com/Danielita473/React18-App.git
```

Once you are done with the cloning process, go to your project folder, open it on your code editor, go to your editor terminal, and install the scripts and dependencies by running `npm install` or `yarn install`. Then, to start the project, do `npm start`. After the app app starts, it should look like this:

![Our app](https://blog.openreplay.com/static/a12a553d64420e1bdb5ae97d6cbc71fc/bb683/image01.png)

We will be working with this in this tutorial.

## Implementing the useTransition()

When you first type in a product number to get a product, you will notice that it updates almost instantly even though it is a super long list of 10,000 items to navigate through. Now, problems begin when you go to the developer tools section of your Chrome browser, go to the performance tab, turn on CPU throttling, and slow down the CPU 4 times.

![Throttling the app](https://blog.openreplay.com/static/ed86da4b643f0dcdb613033ca8f99a7e/972d4/image02.png)

If you are now trying to type in a product number after slowing down the CPU, you will notice that updates get a lot slower and clunky. Even the overall interface looks and feels laggy, especially the input fields, which now feel unresponsive as we are typing and deleting. And this is definitely not a good user experience.

![New experience](https://blog.openreplay.com/7772f35e66497e272d5b34fab617aba9/image03.gif)

You can't see me typing, but the interface is very slow in response, as you can see above. Even before React18, a standard solution was not to work on 10,000 items or products (in our case) at a time. You may use pagination or any other technique or do the filtering on the server side instead of the client side. These are all possible solutions you can consider when encountering problems like this. 

However, if you need to perform this kind of operation on the client-side, i.e., on your client side code, then with React18,  you now have some tools that can give the user a better-perceived performance by delaying some state updating operations by telling React that some updating operations have a higher priority than others. This is the idea behind the concurrency introduced by React 18 and the related hooks and functions. 

`useTransition()` tells React that some state updates have a **lower priority,**, i.e., every other state updates or UI rendering trigger has a higher priority. When we call `useTransition()`, we get an array with exactly two elements: an `isPending` boolean value that indicates if the low-priority state update is still pending, and a `startTransition()` function that you can wrap around a state update to tell React that it's a low-priority update. 

Check out how the `useTransition()` hook can be used. First, go to the `App.js` file and edit the code as seen below:

```javascript
function App() {
  const [isPending, startTransition] = useTransition();
  const [filterTerm, setFilterTerm] = useState('');
  
  const filteredProducts = filterProducts(filterTerm);
  
  function updateFilterHandler(event) {
    startTransition(() => {
      setFilterTerm(event.target.value);
    });
  }
 
  return (
    <div id="app">
      <input type="text" onChange={updateFilterHandler} />
      <ProductList products={filteredProducts} />
    </div>
  );
}
```    

Because `startTransition()` wraps the `setFilterTerm()` state updating function, React gives this state updating code a lower priority. This ensures that the input field remains responsive and responds to keystrokes instantly in the demo app. The application may become unresponsive if `useTransition()` is not used, especially on slower devices. When you type in the product numbers, you will see that the code is now more responsive and far less laggy, even though the CPU has been slowed down 4 times. You can try this out on your system and see the results.

However, you should not start wrapping up all your state updates with `startTransition`. Only use it when you have a slow user interface, especially on older devices, or in a situation where you have no other solution to use. This is because it takes up extra performance.  

## What does `isPending` do?

`isPending` tells you whether there are currently some state updates that are still pending (hasn’t been performed yet by React, and is treated with lower priority. You can use `isPending` to update the UI to show some fallback content while waiting for the main state update to complete. You can see this in the code below in your `App.js` file:

```javascript
return (
    <div id="app">
      <input type="text" onChange={updateFilterHandler} />
      {isPending && <p style={{color: 'white'}}>Updating list..</p>}
      <ProductList products={filteredProducts} />
    </div>
  );
}
```

After implementing the code, you should be able to see something like this when you run the app:

![Enhanced performance](https://blog.openreplay.com/5d88d4e9e08bd6abce3741f1ad4901a4/image04.gif)

So, this is also a feature that you can use when using `useTransition()`. Also, note how much faster it responds after implementing the `useTransition()` feature. 

## Open Source Session Replay

_[OpenReplay](https://github.com/openreplay/openreplay) is an open-source alternative to FullStory and LogRocket. It gives you full observability by replaying everything your users do on your app and showing how your stack behaves for every issue. OpenReplay is self-hosted for full control over your data._

![replayer.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1647097041609/Qi6sMOaaB.png)

_Happy debugging for modern frontend teams - [start monitoring your web app for free](https://github.com/openreplay/openreplay)._



## Implementing useDeferredValue()

`useDeferredValue()` does the same thing as `useTransition()`, making a slow and laggy interface faster. However, it is used in a slightly different way. According to React team member [Dan Abramov](https://twitter.com/dan_abramov), `useDeferredValue()` is mainly

> useful when the value comes "from above" and you don't actually have control over the corresponding `setState` call.

`useTransition()` gives you complete control since you can decide which code should be wrapped and treated as "low priority". However, in some cases, you may not have access to the actual state updating code (for example, if a third-party library handles it), or you can't use `useTransition()` for some reason. This is when `useDeferredValue` can be used instead. You don't wrap the state updating code with `useDeferredValue()`. Instead, you wrap the value generated or updated as a result of the state update (either the state value itself or a value computed based on the state value, for example).

On your `ProductList.js` file, you can edit the code to the one below:

```javascript
import {useDeferredValue} from 'react'

function ProductList({ products }) {
  const deferredProducts = useDeferredValue(products);
  return (
    <ul>
      {deferredProducts.map((product) => (
        <li>{product}</li>
      ))}
    </ul>
  );
}
```    

Here, we use `useDeferredValue()` to wrap `products`. This will result in React performing other state or UI updates with a higher priority than updates related to the products. If you comment out the `isPending` feature and the `startTransition` feature in the `App.js` file and use the `setFilterTerm` as it was before we added `useTransition`, and use `useDeferredValue` as we have done in the code above in the `Product.js` file, then when you go back to your app and try to type in some product numbers, you will see similar results, as we did with `useTransition`. 

## When should they be used, and when not?

As previously stated, `useTransition()` wraps the state updating code, whereas `useDeferredValue()` wraps a value affected by the state change. You don't have to (and shouldn't) utilize both at the same time because they accomplish the same thing.

Instead, if you have access to the state updating code and have some state updates that should be treated with a lower priority, it makes sense to use `useTransition()`. Use `useDeferredValue()` if you don't have that access.

`UseTransition()` and `useDeferredValue()` should not be used to wrap up all of your state updates or values. If you have a complex user interface or component that can't be optimized any other way, you should use the hooks. Other performance enhancements, such as lazy loading, pagination, and performing work in worker threads or on the back end, should always be considered.

## Conclusion

In this article, we went through the similarities and differences between the `useTransition` and `useDeferredValue` hook and how they can help improve the overall user experience. 

[![newsletter](https://blog.openreplay.com/static/e6b18eda7a327511296a2f27692f9c70/e9957/newsletter.png)](https://newsletter.openreplay.com/)