Skip to content

ReactJS - Keys

Key 是在 React 中创建元素列表时需要包含的特殊字符串属性。Key 帮助 React 识别哪些项目已更改、已添加或已移除。为元素提供一个稳定的 Key 对于高效更新和在列表操作时保持组件状态至关重要。

  • 高效更新:Key 使 React 能够执行更高效的 Diffing(差异比较)算法。当列表重新排序时,如果没有 Key,React 可能会重新渲染每个项目。有了 Key,React 可以在不必要地重新渲染的情况下重新排序 DOM 元素。
  • 保持状态:如果你渲染组件列表,当项目重新排序、添加或移除时,Key 有助于保持这些组件的内部状态(例如输入框的值或复选框是否被选中)。

Key 最常见的用例是使用 map() 函数渲染项目列表时。从 map() 返回的每个列表项都应该有一个唯一的 key 属性(prop)。

  • 同级元素中唯一:Key 只需在列表中的同级元素之间保持唯一,无需全局唯一。
  • 稳定且可预测:Key 应该是稳定的。避免使用可能随时间变化的值,例如 Math.random()。如果 Key 发生变化,React 会将该元素视为新元素,销毁旧实例并创建一个新实例(从而丢失状态)。
  • 使用数据 ID:最好的 Key 通常是来自你的数据的唯一 ID(例如数据库 ID)。
  • 索引作为最后的选择:如果项目顺序可能改变,或者可以从列表中间插入/删除项目,通常不建议使用数组索引作为 Key(即 key={index})。这可能导致组件状态和性能问题。但是,如果列表是静态的且项目永不重新排序,则可以使用索引作为 Key。

我们来创建一个简单的项目列表。我们将使用项目的 id 作为 Key。

import React from 'react';
function ListItem({ item }) {
return (
<li>
ID: {item.id} - Name: {item.name}
</li>
);
}
function MyListComponent() {
const items = [
{ id: 'a', name: 'Apple' },
{ id: 'b', name: 'Banana' },
{ id: 'c', name: 'Cherry' }
];
return (
<ul>
{items.map(item => (
<ListItem key={item.id} item={item} />
))}
</ul>
);
}
export default MyListComponent;

在这个示例中,item.id 是一个很好的 Key,因为它对于每个项目都是唯一且稳定的。如果我们添加新项目、移除项目或重新排序项目,React 会使用这些 Key 来高效地更新 DOM 并保持任何 ListItem 组件的状态(如果它们有内部状态)。

示例演示使用 index 作为 Key(并附带注意事项):

import React, { useState } from 'react';
function Content({ componentData }) {
return (
<div>
<div>{componentData.component}</div>
<div>ID from data: {componentData.id}</div>
</div>
);
}
function App() {
const [data, setData] = useState([
{ component: 'First item...', id: 1 },
{ component: 'Second item...', id: 2 },
{ component: 'Third item...', id: 3 },
]);
// Example of adding an item to the beginning, which highlights issues with index keys if items have state
const addItemToBeginning = () => {
const newItem = { component: 'New First item...', id: Date.now() }; // Unique ID
setData([newItem, ...data]);
};
return (
<div>
<button onClick={addItemToBeginning}>Add to Beginning</button>
<div>
{data.map((dynamicComponent, index) => (
<Content
key={index} // Using index as key here
componentData={dynamicComponent}
/>
))}
</div>
<p style={{marginTop: '10px', fontSize: '0.9em', color: 'gray'}}>
注意:在此处(如本例中特定 map 函数所示)使用 'index' 作为 Key 可能会有问题,如果列表项具有内部状态且列表被重新排序或非从末尾插入/删除项目。对于动态列表,优先使用来自数据的稳定、唯一 ID 作为 Key(例如 `key={dynamicComponent.id}`)。
</p>
</div>
);
}
export default App;

要渲染此 App 组件,你的 main.js 或 index.js 文件应如下所示:

import React from 'react';
import ReactDOM from 'react-dom/client'; // Use react-dom/client for React 18+
import App from './App'; // Assuming App.jsx is in the same directory or adjust path
const root = ReactDOM.createRoot(document.getElementById('root')); // Or 'app' if that's your root element ID
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

如果你添加或移除项目,或更改它们的顺序,React 会使用这些 Key 来跟踪每个元素。对于动态列表,使用来自数据的稳定、唯一 ID(例如 dynamicComponent.id)作为 Key 是最稳健的方法。

如需进一步阅读,请查阅 React 官方关于列表和 Key 的文档:https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key