React フラグメントを使うのは避けよう

commits2 min read読了の目安(約2200字 6

次の記事を読んで気になったことを検証した結果、思い込みが明らかになったので書いておきます。

https://zenn.dev/uhyo/articles/usememo-time-cost

Web のハナシであり、 React Native での検証などはやっていません。

TL;DR

  • スタイルを当てないからといって React フラグメントを使うとけっこう遅くなる
    • 元記事の通り div を削ろうとして React フラグメントを使うのは逆効果なのでやめよう
  • ベンチマークは平均ではなく、中央値やパーセンタイルで比較しよう
  • ベンチマークは production ビルドで比較しよう

React フラグメントとは何か?

https://ja.reactjs.org/docs/fragments.html

こういうやつです。

function Fragment() {
  return (
    <>
      <p>ひとつめ</p>
      <p>ふたつめ</p>
    </>
  );
}

React コンポーネントはルートの要素がひとつでないといけないという制限があるため、 React フラグメントを用いてまとめることが可能です。

代替手段というか、自然と手が動く書き方は div を使うものです。

function Div() {
  return (
    <div>
      <p>ひとつめ</p>
      <p>ふたつめ</p>
    </div>
  );
}

この場合、てっきり div のほうが重い処理だと思いこんでいたことが判明しました。

ベンチマーク結果

https://github.com/januswel/react-benchmark

次は prodution ビルドして検証したものです。 DivFragment の項目を見比べてみてください。

median が中央値、 p70 が 70 パーセンタイルです。

中央値は同じ値ですが、 70 パーセンタイルについては React フラグメントを使うコンポーネントが大幅に大きいですね。これはより不安定ということです。ちょっぱやで終わることもあるけど、大抵の場合 div より時間がかかるという結果です。

中央値と 70 パーセンタイルで比較しよう

さて、なぜ中央値と 70 パーセンタイルで比較しているのかについてです。

ブラウザーだけでなく様々なプロセスや I/O が稼働しているコンピューター上でこういった細かいベンチマークを取る場合、些細なことで数値が変動します。平均値はこういった数値変動の影響を受けやすいため、単純比較するのは避けましょう。

中央値ははずれ値の影響が少ない、つまりこういった変動がある環境下での計測による性能比較に向いています。

また、どの程度安定して処理できるのかという点については、平均値付近の値の散らばりを表す分散が使えるのですが、これも平均値同様、はずれ値の影響を受けやすいため、パーセンタイルを使います。

コンピューター上の計測では、割と高い頻度で計測値が変動するため 99 パーセンタイルや 95 パーセンタイルでははずれ値の影響を無視しきれないな、というのが個人的な感覚です。そのため、この記事では 70 パーセンタイルで比較しています。

production ビルドで比較しよう

実際に使われる環境に近い条件で比較したほうが嬉しいからです。

ちなみに production ビルドせずに react-scripts でホストしたときの結果は次です。

中央値でも React フラグメントのほうが大きい値となっています。

70 パーセンタイルの値はどちらの結果でも +0.05 程度です。ベースの数値が低い分、 production ビルドでこの差が大きく響く形となっています。

ベンチマークの取得方法

このへんを見てください。

https://github.com/januswel/react-benchmark/blob/main/src/BenchmarkSuite.jsx

react-component-benchmark パッケージ、便利ですが、こういった感じでユーティリティーを整備してあげたほうが普段使いしやすいですね。

おまけ

BaseLine 、 UseMemo 、 ExtraDiv は元記事と同様のものを修正して数値をとったものです。 production ビルドでは余計な div に対して神経質になる必要はなさそうです。

どこかのタイミングでベンチマークとりながらリファクタリングすればいいんじゃないでしょうか。