React 18の新機能を使ってみた

# はじめに
この記事は[私とあなたの Advent Calendar 2022](https://qiita.com/advent-calendar/2022/trade_eco)の８日目の記事として書かれています。
この記事では、2022年3月29日にリリースされた[React v18.0](https://ja.reactjs.org/blog/2022/03/29/react-v18.html)の新機能を使ってみた感想をまとめようと思います。


# React 18の新機能
React 18 で加わった機能の基盤にあるものは「並行レンダリング」です。

いままでは、始まったレンダリングは中断できず、終わってから次のレンダリングに移行していました。並行レンダリングによって、レンダリングの処理を中断して、あとから中断した処理を再開できるようになります。これにより、レンダリングの最中でもユーザの入力にUIが対応できるようになります。

https://ja.reactjs.org/blog/2022/03/29/react-v18.html

新機能としては「自動バッチング」、「トランジション」、「サスペンスの新機能」の３つになります。

### 自動バッチング
自動バッチングは複数のステート更新を１つの再レンダリングにまとめることです。
React 18以前はイベントハンドラ内の更新のみ自動バッチ処理されていましたが、それ以外のイベントでも自動バッチ処理されるようになりました。

### トランジション
トランジション（段階的推移）はReact 18からの新たな概念として導入されています。トランジションでは更新の緊急性を区別します。
>- 緊急性の高い更新とはタイプ、クリック、プレスといったユーザ操作を直接反映するものです。
>- トランジションによる更新は UI をある画面から別の画面に段階的に遷移させるものです。
> (https://ja.reactjs.org/blog/2022/03/29/react-v18.html#new-feature-transitions)

緊急性の高くない更新では、クリックなどの緊急性の高い更新がやってきたときに中断されます。startTransition API を用いることで、緊急性が高くないもの（トランジション）として扱うことができます。

React 18では`useTransition`のフックも追加されています。
```react:
const [isPending, startTransition] = useTransition();
// https://ja.reactjs.org/docs/hooks-reference.html#usetransition
```
### サスペンスの新機能
サスペンスを用いることで、コンポーネントが処理中で表示できない場合にUIにロード中であることを明示することができます。`<Suspense>`でコンポーネントを囲み、囲んだコンポーネントが表示できないときにfallbackで指定したものを表示することができます。

```react:
<Suspense fallback={<Spinner />}>
  <Comments />
</Suspense>
// https://ja.reactjs.org/blog/2022/03/29/react-v18.html#new-suspense-features
```

# 新機能（トランジション）を使ってみる
今回はトランジションの機能を使って、注文履歴一覧を表示・検索する画面を作りたいと思います。注文履歴は1000件あり、検索して表示するのに時間がかかるようになっています。
トランジションの機能を使う所は、注文履歴の一覧を取得して表示までのローディングの間です。
`isPending`を使って、スピナーを表示するかどうかを判断して、ユーザにローディング状態であることを知らせることができます。

```react:order.tsx
import { useState, useTransition } from "react";

export const OrderList = () => {
    const [text, setText] = useState("");
    const [orderList, setOrderList] = useState<data[]>();
    const [isPending, startTransition] = useTransition();
    const filterData = () => {
      return 以下省略
    };
    const onClickGetData = () => {
        const filteredData = filterData();
        startTransition(() => setOrderList(filteredData));
    }
    return 以下省略
};
```
実際に動かしてみた画面はこちらです。
注文履歴一覧から注文商品が「お茶」であるものを検索して表示されるまでの間にスピナーが表示されているのが確認できます。
また、スピナー表示中も商品検索の部分に文字が入力でき、商品検索のボタンをクリックできる状態になっています。
上記コードの`startTransition`を外すと、文字入力と商品検索のボタンのクリックができませんでした。
![注文履歴2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985914/f24272db-d732-c9ee-02be-478150b0d6e4.gif)


# 感想
- **実装はシンプルだけど、理解するのは難しい**
まずは[公式の文書](https://ja.reactjs.org/blog/2022/03/29/react-v18.html)を読んで、どんな機能が追加されたのか理解するところから始めました。並行レンダリング自体や新しい機能で何が実現できるのかを理解するのに時間がかかりました。
また、実装を進めると新しい機能ではないところで詰まったりしましたが、　最終的にとてもシンプルに実装できることがわかりました。

- **ユーザとしても嬉しい**
表示に時間がかかるレンダリングだとトランジションを使うことで、ユーザがレンダリング中にもUIの入力ができるのでユーザとしても使いやすくなると感じました。

# おわりに
今回は、React 18で追加された新機能を学びながら、簡単な画面を実装してみました。改めて、自分で実装しながら学ぶことの大切さを実感しました。
今回実装した画面はとても簡単なものでしたが、これから実際に表示に時間がかかるレンダリング等に活用できると良さそうです。

# 参考文献
- [React v18.0](https://ja.reactjs.org/blog/2022/03/29/react-v18.html)
- [React 18の新機能と並行レンダリング革命](https://qiita.com/Yuki_Oshima/items/b6ec2fb9f5b5d53381ad)
- [React 18に備えるにはどうすればいいの？　5分で理解する](https://qiita.com/uhyo/items/bbc22022fe846fd2b763)