How the key prop enables React to identify list items and minimize DOM mutations.
When React renders a list of elements, it needs to know which items changed, were added, or were removed between renders. Without the key prop, React uses position-based matching β item at index 0 maps to item at index 0. With keys, React can match items by stable identity across renders, enabling efficient moves instead of destroy-and-recreate.
When your list re-renders, React has two arrays of child elements: the old ones and the new ones. It needs to match them up to decide what to update, what to insert, and what to delete.
React matches elements by their index position. If the list [A, B, C] becomes [B, A, C] (reordered), React sees position 0 changed from A to B and position 1 changed from B to A β causing two updates and potential state loss.
React builds a map from key to fiber. [A, B, C] becoming [B, A, C] is seen as 'key=b moved from position 1 to 0, key=a moved from 1 to 0'. React moves the existing DOM nodes β no destroy/create cycle.
React logs 'Each child in a list should have a unique key prop' when it detects lists without keys. This is a performance warning β your app still works but renders less efficiently.
Changing a component's key tells React 'this is a completely different instance'. React will unmount the old component (running all cleanups) and mount a fresh one. This is useful to reset component state deliberately.
A key that identifies an item across renders β typically a database ID or a slug. Must be unique among siblings.
Using array index as key is safe only for static, non-reordering lists. For dynamic lists, it causes bugs when items reorder.
When React matches an old and new element by key, it reuses the existing DOM node and just updates changed attributes.
Changing a component's key prop intentionally resets it β useful for resetting form state when switching between items.
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.
Keys are React's hint for matching old and new list items. A good key means React can reuse DOM nodes (fast), preserve component state (correct), and trigger minimal updates (efficient). A bad key (or no key) means React either works much harder than necessary or loses component state unexpectedly.
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.