2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ReactのKeyはmap以外にも使えるよ、というおはなし

Posted at

はじめに

Reactで key といえば、多くの場合はリストのレンダリングで利用されることが多いです。

items.map(item => (
  <Item key={item.id} />
))

そのため、

  • mapの時に書くもの
  • 書かないと警告が出るもの

といった認識で止まっている方も多いのではないでしょうか。
(自分も最初はそれくらいの理解でした💦)

しかし、key の本質的な役割は、Componentが「同じものか、別のものか」をReactに伝えるためのものです。

この記事では、key の理解を深めるため、リストに指定する以外のユースケースを紹介したいと思います。

keyの役割とは?

Componentの「同一性」を判断するためのものです。
Reactは再レンダリング時に、前回のUIツリーと今回のUIツリーを比較して差分を更新します。

このときReactが差分の有無の判断材料として利用するのが key です。

具体的には以下のように扱われます。

keyが同じ → 同じComponentとして扱う(更新)
keyが違う → 別のComponentとして扱う(作り直し)

つまり、keyComponentを更新するか、破棄して新しく作るか を決めるための情報です。

※ keyは「再レンダリングを制御するもの」ではなく、あくまで Component の同一性を判断するための情報

keyが変わると何が起きるか

次のようなComponentがあるとします。

function Sample() {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    console.log("mount");
    return () => console.log("unmount");
  }, []);

  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

これを通常どおり使う場合:

<Sample />
  • 親が再レンダリングされても
  • propsが変わっても

Sample は同じComponentとして扱われ、
stateは保持され続けます。

一方で、次のように key を指定すると:

<Sample key={someValue} />

someValue が変わった瞬間、

  1. 以前の Sample は unmount される
  2. 新しい Sample が mount される
  3. stateは初期化される

という挙動になります。

リストのレンダリングで利用する理由

リストでは、

{items.map(item => (
  <Item key={item.id} />
))}

という形で key を指定します。

これは、配列の並びが変わったときに

  • どのComponentが
  • どのComponentに対応しているか

をReactが正しく判断するためです。

つまり、mapで使う keyComponentの同一性を伝えるためのものです。

じゃあ、リスト以外には何に使えるの?

では、リストのレンダリング以外でどんな時に key を使えるのか?
理解の具体例として、以前実際にあった例を簡略化して紹介します。

値がState管理されてしまっているComponent

あるライブラリが、パラメータで渡した値をStateで管理しており、渡す値を変更しても表示が更新されない、という事がありました。

ライブラリ側のComponent(修正できない想定)

import React from "react";

export function MysteriousCreature(input: { initialWord: string }) {
  // !!! パラメータの値をStateに入れてしまっている
  const [memory, _] = React.useState(input.initialWord);

  React.useEffect(() => {
    console.log("👾 Creature mounted");
    return () => console.log("💀 Creature unmounted");
  }, []);

  return (
    <div style={{ border: "1px solid #ccc", padding: "12px", borderRadius: "8px" }}>
      <p>👾 この生き物は記憶を持っているよ!</p>
      <p>記憶:{memory || "(まだ何も覚えてない)"}</p>
    </div>
  );
}

このComponentは、

  • initialWord を初期値として受け取る
  • ただし、初回マウント時にしか使わない
  • propsが変わってもstateは更新されない

という特徴を持っています。

利用側のコンポーネント

import React from "react";
import { MysteriousCreature } from "./mysterious-creature";

function App() {
  const [word, setWord] = React.useState("");
  const [memory, setMemory] = React.useState("");

  return (
    <div style={{ padding: "24px" }}>
      <h2>keyでComponentを“作り直す”例</h2>

      <div
        style={{
          border: "1px solid #ccc",
          padding: "12px",
          borderRadius: "8px",
        }}
      >
        <MysteriousCreature initialWord={memory} />
        <input
          value={word}
          onChange={(e) => setWord(e.target.value)}
          placeholder="言葉を入れてね!"
        />
        <button
          onClick={() => setMemory(word)}
          style={{
            margin: "12px",
            borderRadius: "8px",
          }}
        >
          覚えさせる!
        </button>
      </div>
    </div>
  );
}

export default App;

これを実行してみると、以下のGifのように「記憶」の部分が書き換わってくれません。

Dec-19-2025 04-24-40.gif

対策:Componentにkeyを利用し、「別のComponent」にする

MysteriousCreature は外部ライブラリの実装であるため、呼び出し側で何とか対策をする必要があります。
ここで、keyを利用します。

※ 別Componentであれば、作り直されるReactの特性を利用します

<MysteriousCreature key={memory} initialWord={memory} />

memory が変わるたびに key も変わり、
ReactはComponentを 別物として扱うようになります。

その結果:

  1. 以前のComponentは unmount
  2. 新しいComponentが mount
  3. 初期化処理が再実行される

という流れになり、以下の様に期待する動作をする様になります。

Dec-19-2025 04-31-12.gif

終わりに

今回の例は「そもそもライブラリの実装に問題がある」というものではありますが、
key の性質を理解しておくと、別の事象でハマった際にも役に立つ場面があります。
少しでも key について理解を深めていただけたら幸いです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?