【React】なぜkey propを使うのか

はじめに

みなさん、Reactでkeyを使う理由はご存知ですか?
React がコードの変更点を認識するためだとは聞いたことがあるのではないでしょうか?
ですが、いまいちピンとこないですよね。

そこで、Reactでkeyを使う理由について詳しく調べてみました。
ぜひ最後までご覧ください。

key propとは

前提として、差分アルゴリズムでは、レンダリング間で変化しないキーを維持する際は、仮想DOMツリー内の位置が変わってもその要素はDOMに保持されます。

それを踏まえて、key propが必要な理由は以下の2つです。

  1. 不要な再レンダリングを防ぐため
  2. 再レンダリングさせることでStateをリセットするため

不要な再レンダリングを防ぐため

keyを渡さない場合

keyを渡さない場合、要素リストの更新時にReactはどの要素が変更、追加、または削除されたかを正確に識別できません。その結果、リストに新しい要素が追加されると、既存の要素も再構築されることになり、パフォーマンスの低下をもたらします。

// 変更前
<ul>
  <Question question={q[1]}/>
  <Question question={q[2]}/>
</ul>
// 変更後
<ul>
  // 新しいリストを追加
  <Question question={q[0]}/>

  // 以下は変更前と同じだが、Fiber Tree内の異なる場所に表示されるようになった。
  // 差分アルゴリズムのルールに従って、以下の2つの要素はDOMから削除され、新しい位置に再構築される。
  // パフォーマンス悪い!
  <Question question={q[1]}/>
  <Question question={q[2]}/>
</ul>

keyを渡した場合

keyを渡すことで、Reactは各要素を一意に識別し、リスト内で要素が移動した場合でも変更されていない要素はそのまま再利用することができます。その結果、不要な再レンダリングを防ぎ、パフォーマンスを向上させることができます。

// 変更前
<ul>
  <Question key='q1' question={q[1]}/>
  <Question key='q2' question={q[2]}/>
</ul>
// 変更後
<ul>
  // 新しいリストを追加
  <Question key='q0' question={q[0]}/>

  // 以下の2つの要素はツリーの異なる位置にあるが、安定したキーを持つことになる。
  // つまり、レンダリングを跨いでも再構築されない。
  // パフォーマンス良い!
  <Question key='q1' question={q[1]}/>
  <Question key='q2' question={q[2]}/>
</ul>

再レンダリングさせることでStateをリセットするため

keyを渡さない場合

keyを渡さない場合、コンポーネントのpropsが変更されても、Reactは同じコンポーネントと見なし続けるため、内部状態(State)は保持されます。これは、新しいpropsでコンポーネントを完全にリセットしたい場合には望ましくありません。

以下のサンプルにて、レビューを書いた後、違う商品に切り替えてみてください。

See the Pen Untitled by 山下琳太郎 (@iclrszba-the-sasster) on CodePen.

商品を切り替えたにも関わらず、レビュー内容が引き継がれてしまいます。
本来なら、商品を切り替えたらレビュー内容もリセットして欲しいですね。

keyを渡した場合

異なるkeyをコンポーネントに渡すことで、Reactはそれを新しいコンポーネントとして認識し、以前のコンポーネントとは別に扱います。その結果、コンポーネントは完全に再構築され、内部状態(State)もリセットされます。

See the Pen Untitled by 山下琳太郎 (@iclrszba-the-sasster) on CodePen.

今度は、商品を切り替えたらしっかりとレビュー記載欄もリセットされました。

まとめ

いかがでしたでしょうか?
まとめると、Reactのkey propsには、以下のような役割があります。

  1. 不必要な再レンダリングを避けることでアプリケーションのパフォーマンスを向上。
  2. コンポーネントのStateをリセットする。

ここまでお読みいただきありがとうございました。

参考

リストとkey – React

Understanding the Diffing Algorithm in React.js

差分検出処理 – React

ReactJS Reconciliation – GeeksforGeeks

Reactのパフォーマンス改善や開発効率向上にお困りですか?お気軽にご相談ください。