Join the discussion
Comments
Loading comments...
Cookie preferences
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Join the discussion
Loading comments...
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
key propがReactがリストアイテムを識別してDOM変更を最小化する方法。
Reactがリストのエレメントをレンダリングするとき、レンダリング間でどのアイテムが変更・追加・削除されたかを知る必要があります。key propなしでは、Reactは位置ベースのマッチングを使用します — インデックス0のアイテムはインデックス0のアイテムにマップされます。keyがあれば、Reactはレンダリングをまたいで安定したIDでアイテムをマッチングでき、破棄・再作成ではなく効率的な移動が可能になります。
リストが再レンダリングされると、Reactは2つの子エレメントの配列を持ちます:古いものと新しいもの。何を更新・挿入・削除するかを決めるためにそれらをマッチングする必要があります。
Reactはインデックスの位置でエレメントをマッチングします。リスト[A, B, C]が[B, A, C](並び替え)になると、Reactは位置0がAからBに変わり、位置1がBからAに変わったと見なし — 2つの更新と潜在的なstateの喪失を引き起こします。
Reactはkeyからfiberへのマップを構築します。[A, B, C]が[B, A, C]になることは「key=bが位置1から0に移動、key=aが1から0に移動」と見なされます。Reactは既存のDOMノードを移動します — 破棄・作成サイクルなし。
Reactはkeyなしのリストを検出すると「Each child in a list should have a unique key prop」をログします。これはパフォーマンスの警告です — アプリは動作し続けますが、レンダリングが非効率になります。
コンポーネントのkeyを変更することは、Reactに「これはまったく別のインスタンスだ」と伝えます。Reactは古いコンポーネントをアンマウントし(すべてのクリーンアップを実行)、新しいものをマウントします。これはコンポーネントのstateを意図的にリセットするのに便利です。
レンダリングをまたいでアイテムを識別するkey — 通常はデータベースIDやスラッグ。兄弟要素間で一意である必要があります。
配列インデックスをkeyとして使用することは、静的で並び替えのないリストにのみ安全です。動的なリストでは、アイテムが並び替えられるとバグを引き起こします。
Reactがkeyで古いエレメントと新しいエレメントをマッチングすると、既存のDOMノードを再利用し、変更された属性のみを更新します。
コンポーネントのkey propを意図的に変更するとリセットされます — アイテムを切り替える際にフォームのstateをリセットするのに便利です。
1// ❌ Bad — index as key on dynamic list2{todos.map((todo, index) => (3 <TodoItem key={index} todo={todo} />4))}5// If you delete item at index 0, all items shift — React6// sees every item as 'changed' and re-renders all of them.78// ✅ Good — stable unique ID9{todos.map((todo) => (10 <TodoItem key={todo.id} todo={todo} />11))}12// Deleting one item: React only removes that one node.13// All others are matched by key and kept untouched.1415// 🔄 Intentional reset via key change16<UserProfile key={userId} userId={userId} />17// Changing userId resets all internal state — no need for18// a manual reset effect.
KeyはReactが古いリストアイテムと新しいリストアイテムをマッチングするためのヒントです。良いkeyはReactがDOMノードを再利用でき(高速)、コンポーネントのstateを保持でき(正確)、最小限の更新をトリガーできます(効率的)。悪いkey(またはkeyなし)はReactが必要以上に苦労するか、予期せずコンポーネントのstateを失うことを意味します。
You have a form builder where users can add, remove, and reorder form fields via drag-and-drop. Each field has its own validation state and user input. After reordering, the input values appear in the wrong fields.
Using array index as key means when a user drags field 3 to position 1, React matches the component at position 1 (old field 1) with the new key=1 (field 3's new position). The old component instance retains field 1's input value but now renders field 3's label — a state/UI mismatch.
Assign each form field a stable UUID when created (e.g., `crypto.randomUUID()`). Use this as the key. Now drag-and-drop reordering just changes positions — React recognizes each component by its UUID and moves the DOM nodes without resetting any state.
Takeaway: For any list that supports add, remove, reorder, or filter operations, always use a stable unique ID as the key. Array index only works for truly static, never-reordered lists (like a static navigation menu).
A user profile edit form should reset to clean state whenever the selected user changes. You tried resetting state in useEffect but there's a flash of old data before the reset takes effect.
Setting state in useEffect happens AFTER render and paint. The sequence is: render (shows old user's data) → paint (user sees stale data) → useEffect fires (resets state) → re-render (shows new user's data). This causes a visible flash.
Add `key={userId}` to the form component. When userId changes, React sees a different key at the same position and unmounts the old instance entirely, creating a fresh one. No useEffect needed — the new instance starts with default initial state. Zero flash.
Takeaway: The `key` prop is not just for lists — it's a powerful tool to force React to destroy and recreate a component. Use it whenever you want a 'clean slate' without the complexity and timing issues of manually resetting state in useEffect.