【React 18 新機能】Automatic Batching って何?【初心者にも分かりやすく】

## はじめに
前回に続いて,Reactの新機能の`Automatic Batching`ついて解説していきます！！
React18の中でもかなり重要な機能になっているので、今回の記事を見て概要だけでも
理解しておいてください！

## Automatic Batchingとは...?
以下公式より引用
> バッチングとは React がパフォーマンスのために複数のステート更新をグループ化して、単一の再レンダーにまとめることを指します。自動バッチング以前は、React のイベントハンドラ内での更新のみバッチ処理されていました。promise や setTimeout、ネイティブのイベントハンドラやその他あらゆるイベント内で起きる更新はデフォルトではバッチ処理されていませんでした。自動バッチングにより、これらの更新も自動でバッチ処理されるようになります

端的にいうと、**更新を1回の再レンダリングにまとめることでパフォーマンスを向上させる機能**のことですね。

React18での変更点では、**promise**や**setTimeout**や**then**のイベントにおいても自動的にバッチ処理がされるようになります。
この機能により、**set関数**が呼ばれるたびに再レンダリングされていたのが再レンダリングをまとめて同時に更新して1度で済ませてくれるようなものをReactが内部的に行なってくれます！

概念より、実際にコードを書いて動かした方がわかりやすと思うので動かしてみましょう！

## 実際にコードを動かしてみよう

### Reactバージョン17での挙動

以下の記事を見ながらバージョン17にダウングレードしてください。

https://qiita.com/kim_t0814/items/d90254c807c7280c2db7

実際に動作確認するために、以下のstateを更新するためのファイルを作成してください！

```src/components/AutoBatchiEventHandler.tsx
import { useState } from "react"

export const AutoBatchEventHandler = () => {
  console.log('AutoBatchEventHandler rendered!')
  const [state1, setState1] = useState<number>(0)
  const [state2, setState2] = useState<number>(0)

  const onClickUpdateButton = () => {
    console.log(state1)
    setState1(state1 => state1 + 1)
    console.log(state1)
    setState2(state2 => state2 + 2)
  }
  return (
    <div>
      <p>Automatic Batching確認用(React17)</p>
      <button onClick={onClickUpdateButton}>update state!</button>
      <p>State1: {state1}</p>
      <p>State2: {state2}</p>
    </div>
  )
}
```
呼び出しも元の`App.tsx`は下記のとおり記述してください。

```App.tsx
import './App.css';
import { AutoBatchEventHandler } from './components/AutoBatchEventHandler';

function App() {

  return (
    <div className="App">
      <AutoBatchEventHandler />
    </div>
  );
}

export default App;

```

![REACT17 自動.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/866244c6-f4c2-d330-96c5-97651a67d8b5.gif)


上記の`gif`からも分かるように複数のstate更新があったとしても、再レンダリングは**1度のみ**になるのが
わかるかなと思います。
仮に、イベントハンドラ内で沢山の`state`が更新されたしてもステートの更新処理はバッチ処理1つに
まとめるので再レンダリングは**1度のみ**です！
こちらはReact17にも組み込まれている機能です。

次のイベントハンドラ外での動作も確認したいので以下のファイルを作成してください！

```src/components/AutoBatchOther.tsx
import { useState } from "react"

type Comment = {
  postId: number;
  id: number;
  name: string;
  email: string;
  body: string;
}

export const AutoBatchOther = () => {
  console.log('AutoBatchOther rendered!')

  const [comments, setComments] = useState<Comment[] | null>(null)
  const [isFinishApi, setIsFinishApi] = useState<boolean>(false)
  const [state3, setState3] = useState<string>('')


  const onClickExcuteApi = () => {
    fetch('https://jsonplaceholder.typicode.com/comments/')
      .then(response => response.json())
      .then((data) => {
        setComments(data)
        setIsFinishApi(true)
        setState3('updated')
      })
  }
  return (
    <div>
      <p>Automatic Batching確認用(イベントハンドラ外)</p>
      <button onClick={onClickExcuteApi}>API更新！</button>
      <p>isFinishApi: {isFinishApi ? 'true' : 'false'}</p>
      {comments?.map((comment) => <p key={comment.id}>{comment.body}</p>)}
    </div>

  )
}

```
`App.tsx`
```diff_tsx
 import './App.css';
 import { AutoBatchEventHandler } from './components/AutoBatchEventHandler';
+import { AutoBatchOther } from './components/AutoBatchOther';
 function App() {

   return (
    <div className="App">
      <AutoBatchEventHandler />
+     <AutoBatchOther />
    </div>
   );
 } 

 export default App;

```


`AutoBatchOther.tsx`のコードをかなりざっくり説明するとフェッチAPIを使用して,
コメントの配列を取得してそれを表示するものとなっております。

フェッチAPIについて詳しく知りたい方はこちらをご覧ください。

https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch

データ取得は`json placeholder`を今回は使用しております！

さて挙動を確認していきましょう。

ブラウザ上で実行すると...

![イベントハンドラ外17.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/54aef4b9-ea34-495c-5766-fae4ee0086f8.gif)

上記を見ればわかるかなと思いますが、`onClickExcuteApi`を実行すると3回再レンダリングが走っているかなと思います。
今回は`.then`の中に`set関数`が3回呼ばれているので`gif`のような挙動になっております。

### React18の挙動
まずは`Strictモード`をオフにしてください。
分からない方は以下を参考にしてください。

https://qiita.com/kim_t0814/items/ce95b6b92e7994d4fdac#strict%E3%83%A2%E3%83%BC%E3%83%89%E3%82%92%E3%82%AA%E3%83%95%E3%81%AB%E3%81%97%E3%81%9F%E3%81%84%E9%9A%9B%E3%81%AF

React18でも同様のソースコードを用意してください！！

`Automatic Batching確認用(React17)`を`Automatic Batching確認用(React18)`の
表示名だけ変更して動作確認を行なっていきます。

イベントハンド内はReact17と同様にバッチングされているので**再レンダリング**は1度のみだったかなと思います。
さて本題のイベントハンドラ外の挙動はどうでしょうか。

![react18.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/7f9a786c-6426-f34b-b323-58b76e381b37.gif)

見た通り1度しか再レンダリングされないことが確認出来ていると思います！！
React18にバージョンを上げることで、特に開発者が何もしなくても勝手に**バッチング**してくれます。
まさに、**Automatic Batching**ですね。

#### FlushSyncについて
こちらはバッチ処理を明示的にしないようにすることができます。
使い方は**flushSync**で囲ってあげるだけです。

以下のようにコード追加を行なってください！
`src/components/AutoBatchiEventHandler.tsx`
```diff_tsx
  import { useState } from "react"
+ import { flushSync } from "react-dom"

  export const AutoBatchEventHandler = () => {
    console.log('AutoBatchEventHandler rendered!')
    const [state1, setState1] = useState<number>(0)
    const [state2, setState2] = useState<number>(0)

    const onClickUpdateButton = () => {
      console.log(state1)
+     flushSync(() => {
        setState1(state1 => state1 + 1)
+     })
      console.log(state1)
      setState2(state1 => state1 + 2)
    }
    return (
      <div>
        <p>Automatic Batching確認用(React18)</p>
        <button onClick={onClickUpdateButton}>State更新!</button>
        <p>State1: {state1}</p>
        <p>State2: {state2}</p>
      </div>
    )
  }

```

そうすると...

![ダウンロード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/f66c4ec2-c6fe-91da-c920-e0f69c5afd5f.gif)


gifの通り、Stateが更新される度に**2回再レンダリング**されるのがわかるかなと思います。

## まとめ
今回は**Automatic Batching**についてまとめさせて頂きました。
公式を見て意味がよく分からないという方は、実際に本記事のソースコードを見て
開発環境で実行すると意味合いが分かってくるかなと思います。

**Qiita Engineer Festa**期間中にまた、Reactの新機能について
解説記事の方投稿しようかなと思います。

本記事が皆様の役に立てれば幸いです。


## 参考文献・教材
[React18公式](https://ja.legacy.reactjs.org/blog/2022/03/29/react-v18.html)
[今後のフロントエンド開発で必須知識となるReact v18の機能を丁寧に理解する](https://www.udemy.com/course/react_v18/)