Lists and Keys
下面是JavaScript使用map()
历一个数组,在React中可以使用元素列表来实现相同操作。
//javascript take an array and double them
const numbers = [1,2,3,4,5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);
//React with lists of elements
const numbers = [1,2,3,4,5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
上面的listItems
元素是一个数组,这个数组具有五个元素,每个元素都是一个React elements。
渲染多个元素
你可以建立一个element组,然后通过一个花括号来包裹JSX,下面我们循环遍历numbers
数组,返回一个<li>
元素。我们用一个<ul>
标签包含这个listItems
数组来进行总体渲染。
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
基本列表组件
你可能经常需要在一个组件内渲染一个列表。
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul>{listItems}</ul>
);
}
当运行上面那些代码的时候,会在控制台得到一个warning,这里需要有一个Key元素,这点将在下一个部分讨论。
现在我们需要给每个列表元素分配一个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
Keys帮助React确认哪一个元素被改变、增加或者删除,Keys应该被赋值给数组内部元素,来对数组元素进行一个简单的识别。
const numbers = [1,2,3,4,5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
设置一个元素的Keys值最好的方法是设置一个独一无二的标识,来让其和它的兄弟元素分开,最常使用的是数组的ID作为标识。
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
)
如果没有稳定的ID作为标识,那么需要用数组下标来做标识。但是并不推荐用下标进行标识,如果这些元素需要被重新排列的话,这样会使速度变慢。
使用Keys来拆分组件
Keys只在数组周边的上下文中有效。如果你拆分ListItem
组件,那你需要将key保存在<ListItem/>
元素中,而不是在<li>
元素中。
最好的方法是在每个添加了map()
遍历方法的元素中添加一个Key属性。
function ListItem(props) {
const value = props.value;
return (
<li>
{value}
</li>
);
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((item, index) =>
//Key应当被放在ListItem元素中,而不是li节点中
<ListItem value={item} key={index}/>
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1,23,4,5,6];
ReactDOM.render(
<NumberList numbers={numbers}></NumberList>,
document.getElementById('root')
);
Keys在兄弟节点中必须是不重复的
每个数组元素的Keys值在兄弟节点中应该是独一无二的,然而他们不需要在全局内是独一无二的,我们可以在两个不同的数组中使用相同的Keys值。
function Blog(props) {
const sidebar = (
<ul>
{props.posts.map((post) =>
//这里是第一个使用了post.id作为Key值的地方
<li key={post.id}>
{post.title}
</li>
)}
</ul>
);
const content = props.posts.map((post) =>
//第二个使用post.id作为Key值的地方,两个地方并不冲突。
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
);
return (
<div>
{sidebar}
<hr />
{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的一个提示,但是不能够当做真正的属性来给组件使用,如果组件需要用相同的属性,那么需要单独传递一个属性进去。
const content = posts.map((post) =>
<Post
key={post.id}
id={post.id}
title={post.title}
/>
);
在JSX中插入map()
在JSX中允许插入任何表达式,只要放在花括号里面就可以了:
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number}
/>
)}
</ul>
);
}
有些时候,产生的结果是明码,但是这种风格不能够被滥用,比如JavaScript中,取决于你决定是否值得为了代码的可读性而去拆分组件。