原文地址:https://facebook.github.io/react/docs/lists-and-keys.html
一、Lists
1. 渲染多个组件 (Rendering Multiple Components)
构建元素集合,并使用花括号{}将它们包含在JSX中。
//Warning: Each child in an array or iterator should have a unique "key" prop.
const numbers = [1,2,3,4,5];
const listItems = numbers.map((number)=><li>{number}</li>);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById("root")
);
2. 基本列表组件 (Basic List Component)
在一个组件中渲染列表。
//Warning: Each child in an array or iterator should have a unique "key" prop.
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
“key”是创建元素列表时需要包含的特殊字符串属性。
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
二、Keys
默认情况下,当对DOM节点的子代进行递归时,React只会同时遍历两个子列表,并在有差异时生成一个变异。
eg:
在最后添加一个元素时,这两个树之间的转换效果很好:
//转换前
<ul>
<li>first</li>
<li>second</li>
</ul>
//转换后
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
但是在开始插入元素时,性能会较差。
//转换前
<ul>
<li>first</li>
<li>second</li>
</ul>
//转换后
<ul>
<li>third</li>
<li>first</li>
<li>second</li>
</ul>
反应会使每个子代变异,而不是意识到可以保持< li >first< /li >和< li >second< /li >。
Keys帮助React确定哪些项目已更改,添加或删除。应该给数组中的元素赋予元素一个稳定的标识。
选择密钥的最好方法是使用一个字符串来唯一标识其兄弟之间的列表项。通常会使用数据中的ID作为密钥:
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
当没有稳定ID用于渲染项目时,可以使用项目index作为Keys作为最后的手段:
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
如果项目可以重新排序,我们不建议使用index作为Keys,因为这会很慢。
或者将内容的某些部分哈希生成一个密钥。关键只是在兄弟姐妹中是独一无二的,而不是全局唯一的。
1. 提取组件带Keys (Extracting Components with Keys)
Keys在周围数组的上下文中才有意义。
function ListItem(props) {
// Correct! There is no need to specify the key here:
return <li>{props.value}</li>;
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// Correct! Key should be specified inside the array.
<ListItem key={number.toString()}
value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
一个很好的经验法则是map()调用中的元素需要键。
2. Keys在同级元素中是唯一的 (Keys Must Only Be Unique Among Siblings)
数组中使用的Keys在其兄弟之间应该是唯一的。 然而,它们不需要是全局唯一的。 当我们生成两个不同的数组时,我们可以使用相同的键:
function Blog(props) {
const sidebar = (
<ul>
{props.posts.map((post) =>
<li key={post.id}>
{post.title}
</li>
)}
</ul>
);
const content = (
<ul>
{props.posts.map((post) =>
<li key={post.id}>
{post.title}
</li>
)}
</ul>
);
return (
<div>
{sidebar}
{content}
</div>
);
}
const posts = [
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
<Blog posts={posts} />,
document.getElementById('root')
);
Keys作为React的提示,但不会传递给您的组件。如果组件中需要相同的值,用不同名称作为prop显式传递:
const content = (
<ul>
{props.posts.map((post) =>
<li key={post.id} id={post.id} title={post.title}>
{post.content}
</li>
)}
</ul>
);
渲染后的Blog组件可以看到props.id,却看不到props.key。
3. 在JSX中嵌入map() (Embedding map() in JSX)
JSX允许将任何表达式嵌入到花括号中,所以可以内联map()结果。