はじめに
Reactではコンポーネントに対してkey
を付与できます。
<Component key={key} />
key
の型はstring | number | bigint | null | undefined
です。key
はコンポーネントがUIツリーを構築する際の識別子として役立ちます。
この記事ではkey
がどのように使われてどのような役割を持つかについて解説します。
コンポーネントを繰り返し描画するために使う
key
はコンポーネント内での繰り返し処理を記述する際に使われます。
const Sample: FC = () => {
const users = useUsers();
return (
<div>
{users.map((user) => (
<User
key={user.id}
name={user.name}
mailaddress={user.mailaddress}
/>
)}
</div>
);
};
key
はusers
によって展開された複数のUser
コンポーネント同士を区別するために使われます。
これによって、異なるレンダー間で展開されるコンポーネントの増減や入れ替えをReactが賢く検知して最適なDOMの更新を行うことが可能になります。
繰り返し処理で生成した複数のコンポーネントにkey
がない場合や、key
が重複している場合はコンソール上でエラーが発生します。一見問題なく動いて見えることが多いですが、思わぬバグに繋がったり、Reactが行う最適化の恩恵を受けられないので、コンポーネントにそれぞれ異なるkey
を渡すようにしましょう。
また、レンダー間で同一のコンポーネントには同じkey
を付与してください。以下のように繰り返しのインデックスを元にした値を付与したり、ランダムな値を付与したりするとReactが最適化のための行動を起こせないです。
// インデックス
{users.map((user, idx) => (
<User
key={idx}
name={user.name}
mailaddress={user.mailaddress}
/>
)}
// ランダム
{users.map((user) => (
<User
key={randomUUID()}
name={user.name}
mailaddress={user.mailaddress}
/>
)}
key
を渡すためにコンポーネントの外部で一意の値を生成するか、外部から渡って来た時に持つ位置の値(DBのプライマリーキーなど)を元に作成してください。
コンポーネントをリセットするために使う
レンダー間で異なるkey
をコンポーネントに付与することで、Reactがレンダー前後のコンポーネントを異なるものと判断し、コンポーネントのマウントをやり直します(再レンダリングではないです)。
これによって、対象のコンポーネントの状態をリセットできます。
以下はチェックボックスを切り替えると同時にコンポーネントのkey
を変更するテキストエリアと、key
を付与しないテキストエリアを表示しています。
両方のテキストエリアに文字を入力したのちに、チェックボックスを切り替えると、上のコンポーネントは状態がリセットされて何も入力されていないようになるのに対して下コンポーネントは状態の変化が起きていません。
下のコンポーネントで変化が起きていないのは、ReactはUIツリーにおいて同じ位置で同じコンポーネントがレンダーされるときに状態を引き継いてしまうからです(これは通常自然な挙動で悪い挙動では全くないです)。
このように、key
を変更することでコンポーネントの初期化を行えます。上位のコンポーネントのある状態に依存して、コンポーネントを新しく生成したい場合は状態を初期化する関数を使って手動で行うのではなく、key
を用いて行うことがおすすめです。これによって状態数が変更されることによって生じる初期化の漏れや、実質的に異なるコンポーネントであることを明確にReactに伝えられます。