React

なぜReactではkey propsが必要なのか?

React

Reactで何かのリスト(arrayの中の要素など)をレンダーする際にkey propsをつけ忘れると、warningで怒られた、という経験のある人もいるのではないでしょうか。そして、なんとなくkeyをつけておしまい、という人が多いような気がします(過去の僕も含め。)

この記事で「なぜReactではkey propsを加える必要があるのか」を、まとめます。結論から言えば、key propsはパフォーマンスに影響してきます!

なぜ Reactを使う時にKey props が必要なのか?

一言で言えば、 React の “差分” アルゴリズムの処理に利用されるからです。

それでは、具体例を交えて説明していきます。

子要素の差分検出のプロセス

Reactは、デフォルトの状態(keyをつけていない状態)では、変更前と変更後の両方の子要素リストのそれぞれ先頭の要素から(上から)同時に処理を進め、差分を見つけたところで更新を発生させます。

Key propsを加えなくても特に問題にならないケース

まずは、key propsがなくても問題ないケースをみていきます。下記の例では、上から順番にまず <li>アイテム1</li>を比較、<li>アイテム2</li>を比較、そして<li>アイテム3</li>に到達したところで、差分があると検出し、 <li>アイテム3</li>のみDOMに追加せよと指示を出します。つまり、この例では、key propsを渡してなくても、特にパフォーマンスに問題は生じません。

変更前の仮想DOM

<ul>
  <li>アイテム1</li>
  <li>アイテム2</li>
</ul>

変更後の仮想DOM

<ul>
  <li>アイテム1</li>
  <li>アイテム2</li>
  <li>アイテム3</li>
</ul>

Key propsがないとパフォーマンスに影響が出るケース

次は、key propsないとパフォーマンスに問題が出るケースをみていきます。

下記の例では、小要素の先頭に <li>セルジオ</li>さんが追加されています。

key propsのない状態では、先程の例と同様に、上から順番に比較するので、下記のようになります。

  1.   <li>本田</li><li>セルジオ</li>を比較 =>更新
  2.   <li>久保</li><li>本田</li>を比較 =>更新
  3.   <li>久保</li>を追加の要素と認識 =>更新

つまり、全ての小要素に更新が必要だと判断してしまいます。

このケースでは、実際には

 <li>本田</li>

<li>久保</li>

は、更新の必要がないのに、更新しています。

変更前の仮想DOM

<ul>
  <li>本田</li>
  <li>久保</li>
</ul>

変更後の仮想DOM

<ul>
  <li>セルジオ</li>
  <li>本田</li>
  <li>久保</li>
</ul>

ここで、key props の出番です!

次のセクションで、この例にkey propsを追加してみましょう。

Key propsがないとパフォーマンスに影響が出るケースにkeyを追加する

Reactはkey属性を見つけると、それを元に小要素の比較を行うことができます。デフォルトでは先頭から順番に比較するだけでしたが、今はkey propsがあるので、対応するkeyを検出し、<li key=“4”>本田</li><li key=“17”>久保</li>は、移動しただけで、<li key=“10”>セルジオ</li>が新たに追加された子要素であると判断できます。これにより、先ほどの無駄な子要素の更新を防ぐことができます。

変更前の仮想DOM

<ul>
  <li key=“4”>本田</li>
  <li key=“17”>久保</li>
</ul>

変更後の仮想DOM

<ul>
  <li key=“10”>セルジオ</li>
  <li key=“4”>本田</li>
  <li key=“17”>久保</li>
</ul>

React Key props を実装する時のポイント

  • 表示しようとしている要素が既に固有の ID を持っていれば、そのIDをkeyにすれば良い。
  • key は兄弟要素間でユニークであれば良くて、グローバルでユニークである必要はない。
  • 配列の要素のインデックスを key として渡すことができるが、ソートなどの要素の並び替えがある場合にはパフォーマンスが低下する。よって、インデックスを安易にkeyに設定するのは避けるべき。
  • 不安定な key(例えば Math.random() 関数で生成するような)は多くのコンポーネントのインスタンスと DOM ノードを不必要に再生成し、パフォーマンスの低下や子コンポーネントの state の喪失を引き起こします。

参考サイト

ABOUT ME
Wata
30歳で営業職からエンジニアに転職した者のブログです。 大手海運業→総合商社→ソフトウエアエンジン。現在は、オーストラリアにてエンジニアとして働いています。 未経験からのエンジニアへの転職、フロントエンド周りの技術、エンジニアの仕事環境、趣味の旅行、JAL修行、オーストラリアの情報などを発信しています!

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です