27
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

新規開発や新技術の検証、導入にまつわる記事を投稿しよう!

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

Last updated at Posted at 2023-06-25

はじめに

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

Automatic Batchingとは...?

以下公式より引用

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

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

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

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

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

Reactバージョン17での挙動

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

実際に動作確認するために、以下の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

上記の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

 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について詳しく知りたい方はこちらをご覧ください。

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

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

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

イベントハンドラ外17.gif

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

React18の挙動

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

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

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

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

react18.gif

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

FlushSyncについて

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

以下のようにコード追加を行なってください!
src/components/AutoBatchiEventHandler.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

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

まとめ

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

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

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

参考文献・教材

React18公式
今後のフロントエンド開発で必須知識となるReact v18の機能を丁寧に理解する

27
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?