Getting started with startTransition in React 18
Tags: react, webdev, tutorial, programming
Published: 2021-11-02 16:24:39

**Written by [Arjuna Sky Kok](https://blog.logrocket.com/author/arjunaskykok/)** ✏️

Part of React 18’s experimental Concurrent Mode is a new feature called `startTransition`, which prevents an expensive UI render from being executed immediately.

To understand why we need this feature, remember that forcing expensive UI renders to be done immediately can block lighter and more urgent UI renders from rendering in time. This can frustrate users who need immediate response from the urgent UI renders.

An example of an urgent UI render would be typing in a search bar. When you type, you want to see your typing manifested and begin searching immediately. If the app freezes and the searching stops, you get frustrated. Other expensive UI renders can bog down the whole app, including your light UI renders that are supposed to be fast (like seeing search results as you type).

When developing your React app, you can avoid this problem by [debouncing or throttling](https://blog.logrocket.com/how-and-when-to-debounce-or-throttle-in-react/). Unfortunately, using debouncing or throttling can still cause an app to become unresponsive.

`startTransition` allows you to mark certain updates in the app as non-urgent, so they are paused while the more urgent updates are prioritized. This makes your app feel faster, and can reduce the burden of rendering items in your app that are not strictly necessary. Therefore, no matter what you are rendering, your app is still responding to your user’s input.

In this article, we’ll learn how to use `startTransition` in your React app in order to delay the non-urgent UI updates to avoid blocking urgent UI updates. With this feature, you can convert your slow React app into a responsive one in no time.

Before we begin, note that React 18 is still in alpha at the time of writing, so `startTransition`is not yet part of a stable release.

## Getting started with React 18

Before beginning the tutorial, ensure you have the following:

*   Working knowledge of React
*   Node.js installed on your machine

Let’s begin by creating a React project with create-react-app:

```shell
$ npx create-react-app starttransition_demo
```

The command above created a React project using the latest stable version of React, which is version 17\. We need to use React 18\. Go inside the project directory and remove the `node_modules` directory:

```shell
$ cd starttransition_demo/

$ rm -rf node_modules
```

On Windows, you have to use a different command to remove the directory. After removing the directory, edit `package.json`. Find these lines:

```json
    "react": "^17.0.2",

    "react-dom": "^17.0.2",
```

Then, change the version of React from 17 to alpha:

```json
    "react": "alpha",

    "react-dom": "alpha",
```

Finally, install the libraries with `yarn`:

```shell
$ yarn install
```

To make sure that you have React 18 installed, you can check it from the `node_modules` directory like so:

```shell
$ grep version node_modules/react/package.json

  "version": "18.0.0-alpha-6ecad79cc-20211006",
```

On Windows, you can open the file directly.

Run the server to make sure you can run the React 18 app:

```shell
yarn start
```

Open http://localhost:3000 in your browser. You should see the familiar default page of a React project with a rotating React logo.

## Enabling Concurrent Mode

By default, our React project doesn’t support Concurrent Mode. We need to enable it by rendering the root React node in a different way.

Open `src/index.js`. You can see that we render the root node with the `render` static method from `ReactDOM`:

```javascript
ReactDOM.render(

  &lt;React.StrictMode>

    &lt;App />

  &lt;/React.StrictMode>,

  document.getElementById('root')

);
```

To enable Concurrent Mode, we need to create the root node first then use the `render` method from that instance. Change the lines above to the lines below:

```javascript
const container = document.getElementById('root')

const root = ReactDOM.createRoot(container);

root.render(

  &lt;React.StrictMode>

    &lt;App />

  &lt;/React.StrictMode>

);
```

Notice the `createRoot` method from `ReactDOM`. This will create a root node.

## Setting up a testing environment

First, let’s create a React app with a light UI render and an expensive UI render. Open `src/App.js`. You can see the `App` function definition displaying a React logo, a `p` tag, and a link.

Replace the `App` function with the code below:

```javascript
function App() {

  const [search_text, setSearchText] = useState("");

  const [search_result, setSearchResult] = useState();

  const handleChange = e => {

    setSearchText(e.target.value);

  };

  useEffect(() => {

    if (search_text==="") {

        setSearchResult(null);

    } else {

        const rows = Array.from(Array(5000), (_, index) => {

              return (

                      &lt;div key={index}>

                    &lt;img src={logo} className="App-logo" alt="logo" />

                    &lt;div>{index + 1}. {search_text}&lt;/div>

                      &lt;/div>

                );

        });

        const list = &lt;div>{rows}&lt;/div>;

        setSearchResult(list);

    }

  }, [search_text]);

  return (

    &lt;div className="App">

        &lt;header className="App-header">

            &lt;div className="SearchEngine">

                &lt;div className="SearchInput">

                    &lt;input type="text" value={search_text} onChange={handleChange} />

                &lt;/div>

                &lt;div className="SearchResult">

                    {search_result}

                &lt;/div>

            &lt;/div>

        &lt;/header>

    &lt;/div>

  );

}
```

You need to import `useEffect` and `useState`. Put this line on top of the file:

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

Here, we are creating the app’s UI that consists of two parts: the search input and the search result.

Because the input has a callback, when you type the text on the input, the text is passed as an argument to `setSearchText` to update the value of `search_text` using the `useState` hook. Then, the search result shows up. For this demo, the result is 5,000 rows where each row consists of a rotating React logo and the same search query text.

Our light and immediate UI render is the search input with its text. When you type text on the search input, the text should appear immediately. However, displaying 5,000 React logos and the search text is an expensive UI render.

Let’s look at an example; try typing “I love React very much” quickly in our new React app. When you type “I”, the app renders the text “I” immediately on the search input. Then it renders the 5,000 rows. This takes a long time, which reveals our rendering problem. The React app cannot render the full text immediately. The expensive UI render makes the light UI render become slow as well.

You can try it yourself on the app at [http://localhost:3000](http://localhost:3000). You’ll be presented with a search input. I have set up [a demo app](https://codepen.io/arjunaskykok/pen/XWarryy) as well.

![Screenshot of sample React app with searchbar that reads "I love React very much"](https://blog.logrocket.com/wp-content/uploads/2021/10/React-sample-app.png)

What we want is for the expensive UI render not to drag the light UI render to the mud while it loads. They should be separated, which is where `startTransition` comes in.

## Using `startTransition`

Let’s see what happens when we import `startTransition`. Your top line import should be like this:

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

Then, wrap the expensive UI render in this function. Change `setSearchResult(list)` into the code below:

```javascript
      startTransition(() => {

          setSearchResult(list);

      });
```

Now, you can test the app again. When you type something in the search input, the text is rendered immediately. After you stop (or a couple of seconds pass), the React app renders the search result.

What if you want to display something on the search results while waiting for the expensive UI render to finish? You may want to display a progress bar to give immediate feedback to users so they know the app is working on their request.

For this, we can use the `isPending` variable that comes from the `useTransition` hook.

First, change the import line on the top of the file into the code below:

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

Extract `isPending` and `startTransition` from the `useTransition` hook. Put the code below on the first line inside the `App` function:

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

Next, change the content of `&lt;div className="SearchResult">` to the code below:

```javascript
            {isPending && &lt;div>&lt;br />&lt;span>Loading...&lt;/span>&lt;/div>}

            {!isPending && search_result}
```

Now when you type the text on the search input very fast, the loading indicator is displayed first.

![Screenshot of search bar in React app with Loading indicator](https://blog.logrocket.com/wp-content/uploads/2021/10/Sample-React-app-loading.png)

## Conclusion

With `startTransition`, you can make the React app smooth and reactive by separating the immediate UI renders and the non-urgent UI renders. By putting all non-urgent UI renders inside the `startTransition` method, your app will be much more satisfying to use.

We also covered using the `isPending` variable to indicate the status of the transition in case you want to give feedback to users.

You can get the full code of the [`startTransition` demo app](https://github.com/arjunaskykok/starttransition_demo) here. You can also experiment with the [demo of the app](https://codepen.io/arjunaskykok/pen/xxrvNMN) to your heart's content. Hopefully this knowledge will be useful for you when you build your next React app. Make sure the apps will be smooth!

---

## Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, [try LogRocket](https://www2.logrocket.com/react-performance-monitoring). 

[![LogRocket Dashboard Free Trial Banner](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)](https://www2.logrocket.com/react-performance-monitoring)

[LogRocket](https://www2.logrocket.com/react-performance-monitoring) is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — [start monitoring for free](https://www2.logrocket.com/react-performance-monitoring).