💡

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

に公開

はじめに

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

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

key propとは

ある要素がユニークであることを差分アルゴリズムに伝えるための特別なpropsです。
各コンポーネント・インスタンスに一意の識別子を与えることができ、Reactが同じコンポーネント・タイプの複数のインスタンスを区別できるようになります。

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でコンポーネントを完全にリセットしたい場合には望ましくありません。

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

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

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

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

まとめ

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

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

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

ちなみに、keyにindexを渡すのはアンチパターンです!
詳しくは以下を参考にしてみてください!
https://zenn.dev/luvmini511/articles/f7b22d93e9c182
https://robinpokorny.medium.com/index-as-a-key-is-an-anti-pattern-e0349aece318
https://jsbin.com/wohima/edit?output

参考

https://ja.legacy.reactjs.org/docs/lists-and-keys.html
https://peeyushjss.medium.com/understanding-the-diffing-algorithm-in-react-js-9e9b71940341
https://ja.legacy.reactjs.org/docs/reconciliation.html#the-diffing-algorithm
https://www.geeksforgeeks.org/reactjs-reconciliation/

Discussion