はじめに
前回に続いて,Reactの新機能のAutomatic Batching
ついて解説していきます!!
React18の中でもかなり重要な機能になっているので、今回の記事を見て概要だけでも
理解しておいてください!
Automatic Batchingとは...?
以下公式より引用
バッチングとは React がパフォーマンスのために複数のステート更新をグループ化して、単一の再レンダーにまとめることを指します。自動バッチング以前は、React のイベントハンドラ内での更新のみバッチ処理されていました。promise や setTimeout、ネイティブのイベントハンドラやその他あらゆるイベント内で起きる更新はデフォルトではバッチ処理されていませんでした。自動バッチングにより、これらの更新も自動でバッチ処理されるようになります
端的にいうと、更新を1回の再レンダリングにまとめることでパフォーマンスを向上させる機能のことですね。
React18での変更点では、promiseやsetTimeoutやthenのイベントにおいても自動的にバッチ処理がされるようになります。
この機能により、set関数が呼ばれるたびに再レンダリングされていたのが再レンダリングをまとめて同時に更新して1度で済ませてくれるようなものをReactが内部的に行なってくれます!
概念より、実際にコードを書いて動かした方がわかりやすと思うので動かしてみましょう!
実際にコードを動かしてみよう
Reactバージョン17での挙動
以下の記事を見ながらバージョン17にダウングレードしてください。
実際に動作確認するために、以下のstateを更新するためのファイルを作成してください!
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
は下記のとおり記述してください。
import './App.css';
import { AutoBatchEventHandler } from './components/AutoBatchEventHandler';
function App() {
return (
<div className="App">
<AutoBatchEventHandler />
</div>
);
}
export default App;
上記のgif
からも分かるように複数のstate更新があったとしても、再レンダリングは1度のみになるのが
わかるかなと思います。
仮に、イベントハンドラ内で沢山のstate
が更新されたしてもステートの更新処理はバッチ処理1つに
まとめるので再レンダリングは1度のみです!
こちらはReact17にも組み込まれている機能です。
次のイベントハンドラ外での動作も確認したいので以下のファイルを作成してください!
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
を今回は使用しております!
さて挙動を確認していきましょう。
ブラウザ上で実行すると...
上記を見ればわかるかなと思いますが、onClickExcuteApi
を実行すると3回再レンダリングが走っているかなと思います。
今回は.then
の中にset関数
が3回呼ばれているのでgif
のような挙動になっております。
React18の挙動
まずはStrictモード
をオフにしてください。
分からない方は以下を参考にしてください。
React18でも同様のソースコードを用意してください!!
Automatic Batching確認用(React17)
をAutomatic Batching確認用(React18)
の
表示名だけ変更して動作確認を行なっていきます。
イベントハンド内はReact17と同様にバッチングされているので再レンダリングは1度のみだったかなと思います。
さて本題のイベントハンドラ外の挙動はどうでしょうか。
見た通り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の通り、Stateが更新される度に2回再レンダリングされるのがわかるかなと思います。
まとめ
今回はAutomatic Batchingについてまとめさせて頂きました。
公式を見て意味がよく分からないという方は、実際に本記事のソースコードを見て
開発環境で実行すると意味合いが分かってくるかなと思います。
Qiita Engineer Festa期間中にまた、Reactの新機能について
解説記事の方投稿しようかなと思います。
本記事が皆様の役に立てれば幸いです。