ReactJS - Keys
ReactJS - Key
Section titled “ReactJS - Key”Key 是在 React 中创建元素列表时需要包含的特殊字符串属性。Key 帮助 React 识别哪些项目已更改、已添加或已移除。为元素提供一个稳定的 Key 对于高效更新和在列表操作时保持组件状态至关重要。
Key 为何重要?
Section titled “Key 为何重要?”- 高效更新:Key 使 React 能够执行更高效的 Diffing(差异比较)算法。当列表重新排序时,如果没有 Key,React 可能会重新渲染每个项目。有了 Key,React 可以在不必要地重新渲染的情况下重新排序 DOM 元素。
- 保持状态:如果你渲染组件列表,当项目重新排序、添加或移除时,Key 有助于保持这些组件的内部状态(例如输入框的值或复选框是否被选中)。
在列表中使用 Key
Section titled “在列表中使用 Key”Key 最常见的用例是使用 map() 函数渲染项目列表时。从 map() 返回的每个列表项都应该有一个唯一的 key 属性(prop)。
Key 的最佳实践:
Section titled “Key 的最佳实践:”- 同级元素中唯一:Key 只需在列表中的同级元素之间保持唯一,无需全局唯一。
- 稳定且可预测:Key 应该是稳定的。避免使用可能随时间变化的值,例如
Math.random()。如果 Key 发生变化,React 会将该元素视为新元素,销毁旧实例并创建一个新实例(从而丢失状态)。 - 使用数据 ID:最好的 Key 通常是来自你的数据的唯一 ID(例如数据库 ID)。
- 索引作为最后的选择:如果项目顺序可能改变,或者可以从列表中间插入/删除项目,通常不建议使用数组索引作为 Key(即
key={index})。这可能导致组件状态和性能问题。但是,如果列表是静态的且项目永不重新排序,则可以使用索引作为 Key。
示例:使用 Key 渲染列表
Section titled “示例:使用 Key 渲染列表”我们来创建一个简单的项目列表。我们将使用项目的 id 作为 Key。
components/MyListComponent.jsx
Section titled “components/MyListComponent.jsx”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(并附带注意事项):
App.jsx (演示用,不总是推荐)
Section titled “App.jsx (演示用,不总是推荐)”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 文件应如下所示:
main.js / index.js
Section titled “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 IDroot.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