Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

React の key をちゃんと使えないと起こる問題

「React の key に配列の添え字を使ってはいけない」理由を説明できますか?

リスト以外で key を使うべき場面をご存じですか?

今回は React の key を適切に扱えないと起こる問題を紹介します。

ダメな例のデモ

まず、key を適切に設定していない、keyをつけるべき場面を実際にご覧ください。

key をつけるべきなのにつけていない codesandbox.io

key を適切に設定していない(index で設定してしまっている) codesandbox.io

問題1: key をつけるべきなのにつけていない

recursing-fermi-6bm9c - CodeSandbox

確認手順:

  1. 「change」ボタンをクリックする
  2. 色名がすぐに Green へ変化する
  3. 画像のほうは以前のものがしばらく(新しい画像の読み込みが終わるまで)表示され続ける

このように色名と画像がズレるのは意図していません。

どうして起きるのか?

change ボタンを押したとき React からすると「img の src が変わっただけ」に見えます。 そのため、React は同じ img 要素を使って src だけ変えます。同じ img 要素なので、以前の画像がキャッシュされ、新しい画像を読み込むまで古い画像を表示し続けます。

解決方法: key を設定する

解決するには、React へ img 要素を新しい img 要素で置き換えるよう指示 すれば OK です。そして、ここで使うのが key prop です。key を使えば React に「img 要素が新しくなった」と伝えられます。新しい画像 URL がセットされた新しい img が追加されれば、古い画像が表示されることはありません。

問題2: key を適切に設定していない

zealous-lehmann-luycv - CodeSandbox

こちらは key に配列の添え字を渡してしまっているパターンです。要素を削除したときに問題が起こっています。

確認手順:

  1. 1つ目の delete ボタンを押す
  2. input の値が Blue のままになっている

どうして起きるのか?

これも先ほどの例と同じで、要素が削除されても React からすると「最後の要素が削除された」ように見えるため、1つ目の DOM を使いまわそうとするためです。

解決方法: 要素ごとにユニークな値を key にする

これを解決するには、要素ごとにユニークな値を使えば OK です。key は「ある要素と DOM の対応付けをしている」と考えれば腑に落ちるでしょう(間違えた例では index が同じなのだから input の値が変わらないのは当然)。

まとめ: コンポーネントが内部に状態を持っているときは key に気を付ける

見てきた例は2つとも、コンポーネントが内部に状態を持っていた(img と input)のが原因でした。内部の状態を引き継がせたくない場合は、しっかりと key を設定しましょう。

(もちろん各人が作った React コンポーネントも内部に状態を持っていれば同じような問題が起こります)