React フラグメントを使うのは避けよう
次の記事を読んで気になったことを検証した結果、思い込みが明らかになったので書いておきます。
Web のハナシであり、 React Native での検証などはやっていません。
TL;DR
- スタイルを当てないからといって React フラグメントを使うとけっこう遅くなる
- 元記事の通り div を削ろうとして React フラグメントを使うのは逆効果なのでやめよう
- ベンチマークは平均ではなく、中央値やパーセンタイルで比較しよう
- ベンチマークは production ビルドで比較しよう
React フラグメントとは何か?
こういうやつです。
function Fragment() {
return (
<>
<p>ひとつめ</p>
<p>ふたつめ</p>
</>
);
}
React コンポーネントはルートの要素がひとつでないといけないという制限があるため、 React フラグメントを用いてまとめることが可能です。
代替手段というか、自然と手が動く書き方は div を使うものです。
function Div() {
return (
<div>
<p>ひとつめ</p>
<p>ふたつめ</p>
</div>
);
}
この場合、てっきり div
のほうが重い処理だと思いこんでいたことが判明しました。
ベンチマーク結果
次は prodution ビルドして検証したものです。 Div
と Fragment
の項目を見比べてみてください。
median が中央値、 p70 が 70 パーセンタイルです。
中央値は同じ値ですが、 70 パーセンタイルについては React フラグメントを使うコンポーネントが大幅に大きいですね。これはより不安定ということです。ちょっぱやで終わることもあるけど、大抵の場合 div より時間がかかるという結果です。
中央値と 70 パーセンタイルで比較しよう
さて、なぜ中央値と 70 パーセンタイルで比較しているのかについてです。
ブラウザーだけでなく様々なプロセスや I/O が稼働しているコンピューター上でこういった細かいベンチマークを取る場合、些細なことで数値が変動します。平均値はこういった数値変動の影響を受けやすいため、単純比較するのは避けましょう。
中央値ははずれ値の影響が少ない、つまりこういった変動がある環境下での計測による性能比較に向いています。
また、どの程度安定して処理できるのかという点については、平均値付近の値の散らばりを表す分散が使えるのですが、これも平均値同様、はずれ値の影響を受けやすいため、パーセンタイルを使います。
コンピューター上の計測では、割と高い頻度で計測値が変動するため 99 パーセンタイルや 95 パーセンタイルでははずれ値の影響を無視しきれないな、というのが個人的な感覚です。そのため、この記事では 70 パーセンタイルで比較しています。
production ビルドで比較しよう
実際に使われる環境に近い条件で比較したほうが嬉しいからです。
ちなみに production ビルドせずに react-scripts
でホストしたときの結果は次です。
中央値でも React フラグメントのほうが大きい値となっています。
70 パーセンタイルの値はどちらの結果でも +0.05 程度です。ベースの数値が低い分、 production ビルドでこの差が大きく響く形となっています。
ベンチマークの取得方法
このへんを見てください。
react-component-benchmark パッケージ、便利ですが、こういった感じでユーティリティーを整備してあげたほうが普段使いしやすいですね。
おまけ
BaseLine 、 UseMemo 、 ExtraDiv は元記事と同様のものを修正して数値をとったものです。 production ビルドでは余計な div に対して神経質になる必要はなさそうです。
どこかのタイミングでベンチマークとりながらリファクタリングすればいいんじゃないでしょうか。
Discussion
興味深い比較ありがとうございます!
記事中で
Flagment
と書いていましたが実際はFragment
なので念のためお伝えします!ご指摘ありがとうございます
なおしました!
お恥ずかしい…
そもそもFragmentってなんであるんだっけ? というところが気になってドキュメントを眺めていたのですが、ドキュメントには一言も「パフォーマンスのために作った」なんて書いていないのですね。
ValidなHTMLを書きやすくするための工夫だったのでした。。。(私はなぜか、綺麗なHTMLを出力するためのものだったり、パフォーマンスの観点で有利なコンポーネントを書くためと認識していました)
僕もその認識でした
また、同様に React コンポーネントのレンダリング速度の計測がすっぽり抜け落ちていたので、念のためにやってみたら面白い結果が出たので書いてみました
divとfragmentのパフォーマンス比較はおもしろいですが、この調査から僕が思うのは、「React フラグメントを使うのは避けよう」ではなく、この程度の差ならパフォーマンスのためと言ってfragmentが適切なところをあえてdivで囲むなんてしなくていいってことですかね。
そこはプロジェクトの性能要件や個人の好みで判断すべきところですね
個人的には、大きめのプロダクトであれば積もり積もって無視できないパフォーマンスになるかな、と感じています