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 属性如何使 React 识别列表项并最小化 DOM 变更。
当 React 渲染元素列表时,它需要知道在两次渲染之间哪些项目发生了变化、被添加或被删除。没有 key prop,React 使用基于位置的匹配 — 索引 0 的项映射到索引 0 的项。有了 keys,React 可以通过稳定的标识跨渲染匹配项目,实现高效的移动而不是销毁和重建。
当列表重新渲染时,React 有两个子元素数组:旧的和新的。它需要将它们匹配起来,以决定更新什么、插入什么、删除什么。
React 通过索引位置匹配元素。如果列表 [A, B, C] 变为 [B, A, C](重新排序),React 看到位置 0 从 A 变为 B,位置 1 从 B 变为 A — 导致两次更新和潜在的 state 丢失。
React 构建从 key 到 Fiber 的映射。[A, B, C] 变为 [B, A, C] 被视为 'key=b 从位置 1 移到 0,key=a 从 1 移到 0'。React 移动现有 DOM 节点 — 没有销毁/创建周期。
当 React 检测到没有 keys 的列表时,会记录 'Each child in a list should have a unique key prop'。这是性能警告 — 你的应用仍然工作但渲染效率较低。
更改组件的 key 告诉 React '这是一个完全不同的实例'。React 将卸载旧组件(运行所有清理操作)并挂载一个全新的。这对故意重置组件 state 很有用。
跨渲染标识项目的 key — 通常是数据库 ID 或 slug。在兄弟元素中必须唯一。
将数组索引用作 key 仅对静态、不重新排序的列表安全。对于动态列表,在项目重新排序时会导致 bug。
当 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.
Keys 是 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.