React 18 New Hooks for Concurrency!
Tags: react, webdev, beginners, news
Published: 2022-04-13 14:44:17

Concurrency is an important change in `React 18`.

I'm going to look at the following hooks.

* `useId` useId is a new hook for generating unique IDs on both the client and server while avoiding hydration mismatches. It is primarily useful for component libraries integrating with accessibility APIs that require unique IDs. This solves an issue that already exists in React 17 and below, but it’s even more important in React 18 because of how the new streaming server renderer delivers HTML out-of-order. [See docs here.](https://reactjs.org/blog/2022/03/29/react-v18.html#useid)
* `useTransition` useTransition and startTransition let you mark some state updates as not urgent. Other state updates are considered urgent by default. React will allow urgent state updates (for example, updating a text input) to interrupt non-urgent state updates (for example, rendering a list of search results). [See docs here](https://reactjs.org/blog/2022/03/29/react-v18.html#usetransition)
* `useDeferredValue` useDeferredValue lets you defer re-rendering a non-urgent part of the tree. It is similar to debouncing, but has a few advantages compared to it. There is no fixed time delay, so React will attempt the deferred render right after the first render is reflected on the screen. The deferred render is interruptible and doesn’t block user input. [See docs here.](https://reactjs.org/blog/2022/03/29/react-v18.html#usedeferredvalue)

I will explain these hooks with code. Not thoroughly.
I just want to give you a quick view.

If you want to know more detail, google for it and you will be able to find a lot of materials online.

---

Before starting it, if you use `ReactDOM.render` replace it with `createRoot`.

*`createRoot`: New method to create a root to render or unmount. Use it instead of ReactDOM.render. New features in React 18 don’t work without it. [See docs here.](https://reactjs.org/blog/2022/03/29/react-v18.html#react-dom-client)

I just set it up like this.

```typescript
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';

const container = document.getElementById('root') || document.body;
const root = createRoot(container);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
```

---

### useId

Have you used `uuid` to generate uniqueid for identifying nodes or something else before?
You can use 'useId' now.

```typescript
import React, {
  useState,
  useCallback,
  useMemo,
  useRef,
  useEffect,
  useId,
} from 'react';

interface TimerItem {
  id: string;
  createdAt: Date;
  tm: NodeJS.Timeout;
}

let num = 1;
let count = () => {
  return num++ % 10000;
};

function Timer() {
  const [timers, setTimers] = useState<TimerItem[]>([]);
  const [workIn, setWorkIn] = useState(false);
  const id = useId(); // generate uniqueId
  const delUniqueId = useRef<string | null>(null);

  const toggle = useCallback(() => setWorkIn((prev) => !prev), []);

  const addTimer = useCallback(() => {
    // create new timer
    const itemId = `${id}${count()}`;
    const newItem = {
      id: itemId,
      createdAt: new Date(),
      tm: setTimeout(() => {
        const tmInv = setInterval(() => {
          if (!delUniqueId.current) {
            // insert this uniqueId into delUniqueId to remove and execute worker using toggle
            delUniqueId.current = itemId;
            toggle();
            // if delUniqueId is changed successfully, clear this timer
            clearInterval(tmInv);
          }
        }, 50);
      }, 2000),
    };

    setTimers((prevTimers) => [...prevTimers, newItem]);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (!delUniqueId.current) return;

    // remove a timer by delUniqueId
    setTimers(timers.filter((t) => t.id !== delUniqueId.current));
    delUniqueId.current = null;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [workIn]);

  const children = useMemo<React.ReactNode>(() => {
    return (
      <>
        {timers.map((timer) => (
          <div key={timer.id}>
            <span>
              Timer / {timer.id} / {timer.createdAt.getMinutes()}::
              {timer.createdAt.getSeconds()}
            </span>
          </div>
        ))}
      </>
    );
  }, [timers]);

  return (
    <div>
      <button onClick={addTimer}>Add Timer</button>
      <hr />
      {children}
    </div>
  );
}

function App() {
  return (
    <>
      <Timer />
      <Timer />
      <Timer />
    </>
  );
}
```

![useid example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gffisqm9581obnpmbaqf.gif)


It renders three `Timer`. each timer component has uniqueid. You can identify with the id whose the data.

Did you see **:r1:**, **:r3:**, **:r5:**?

Yes, I'm not sure if it's a good example.

Anyway, you can use `useId` to generate uniqueid.

But, please note that
>useId is not for generating keys in a list. Keys should be generated from your data.* [See docs](https://reactjs.org/blog/2022/03/29/react-v18.html#useid)

### useTransition, startTransition

some state updates as not urgent and other state updates are considered urgent by default?

Use `startTransition` for non-urgent state updates.

```typescript
import React, {
  useEffect,
  useState,
} from 'react';

const nodes: React.ReactNode[] = [];

for (let i = 1; i <= 5000; i++) {
  nodes.push(<div>{Math.random() * i}</div>);
}

function App() {
  const [text, setText] = useState('');
  const [random, setRandom] = useState<React.ReactNode[]>([]);

  useEffect(() => {
    if (!text) return;
      setRandom(nodes);
  }, [text]);

  return (
    <>
      <input
        type="text"
        onChange={(e) => setText(e.target.value)}
        value={text}
      />
      <>{random}</>
    </>
  );
}
```


![not using starttransition](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1d57z7hlkar4vn43080o.gif)

Here is an example.
As you see, it almost stopped typing when I type.

If you consider other components rendering(below random number list) is not urgent, you can use 'startTransition' like this.

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

const nodes: React.ReactNode[] = [];

for (let i = 1; i <= 5000; i++) {
  nodes.push(<div>{Math.random() * i}</div>);
}

function App() {
  const [text, setText] = useState('');
  const [random, setRandom] = useState<React.ReactNode[]>([]);

  useEffect(() => {
    if (!text) return;
    startTransition(() => {
      setRandom(nodes);
    });
  }, [text]);

  return (
    <>
      <input
        type="text"
        onChange={(e) => setText(e.target.value)}
        value={text}
      />
      <>{random}</>
    </>
  );
}
```


![start Transition](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/saz6aaxkgpf6d8crkl8o.gif)

Although there is a bit stop(other components have to render anyway), it was certainly better than before.

If you need a loading something, you can use `useTransition`

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

const nodes: React.ReactNode[] = [];

for (let i = 1; i <= 5000; i++) {
  nodes.push(<div>{Math.random() * i}</div>);
}

function App() {
  const [text, setText] = useState('');
  const [random, setRandom] = useState<React.ReactNode[]>([]);
  const [isPending, startTransition] = useTransition();

  useEffect(() => {
    if (!text) return;
    startTransition(() => {
      setRandom(nodes);
    });
  }, [text]);

  return (
    <>
      <input
        type="text"
        onChange={(e) => setText(e.target.value)}
        value={text}
      />
      {isPending ? 'loading...' : <>{random}</>}
    </>
  );
}
```

![useTransition](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydfpv2c7j3py2xku2fz0.gif)

### useDeferredValue

Something's change affects other renderings?
But you have to render something's change first and it's okay that the other follows behind it?

Use `useDeferredValue`.

```typescript
import React, { useState, useMemo } from 'react';

function App() {
  const [text, setText] = useState('');

  const random = useMemo<React.ReactNode>(() => {
    const children: React.ReactNode[] = [];

    for (let i = 1; i <= 3000; i++) {
      children.push(<div>{Math.random() * i}</div>);
    }

    return children;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [text]);

  return (
    <>
      <input
        type="text"
        onChange={(e) => setText(e.target.value)}
        value={text}
      />
      <>{random}</>
    </>
  );
}
```


![Not using useDeferredValue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eue635zm2l2leb08ewpg.gif)

Here is an example.
It renders 3000 random nodes depending on the text's change.
There is a lot of delays, right?

Let's use `useDeferredValue`

```typescript
import React, { useDeferredValue, useState, useMemo } from 'react';

function App() {
  const [text, setText] = useState('');
  const deferredText = useDeferredValue(text);

  const random = useMemo<React.ReactNode>(() => {
    const children: React.ReactNode[] = [];

    for (let i = 1; i <= 1000; i++) {
      children.push(<div>{Math.random() * i}</div>);
    }

    return children;
  }, [deferredText]);

  return (
    <>
      <input
        type="text"
        onChange={(e) => setText(e.target.value)}
        value={text}
      />
      <>{random}</>
    </>
  );
}
```


![useDeferredValue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yxlq54svcu3th4dsey3t.gif)

![consolelog value and deferredvalue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/usgj35ppb9yqg5ddjbmw.png)


We used **deferredText** as a dependency of the useMemo.
It's similar to debouncing.

---

## Conclusion

React 18 New Hooks! There are other new features.
I'd recommend you google them before applying them to your project.
Make your strategies in concurrent rendering for your users.

`React` has given us another power :)

Happy coding!