首先,让我们回顾一下在JavaScript中如何给list变形的。
如下述代码,我们用map()函数循环numbers数组将其中的值加倍。我们给map()返回的新数字组分配加倍的值并打印它:
const numbers=[1,2,3,4,5];
const doubled=numbers.map((number)=>number*2);
console.log(doubled);
这些代码打印[2,4,6,8,10]到平台上。
在React中,将数组转换成元素列表几乎是完全相同的事。
渲染多个组件
你可以创建元素集合用{}括住。以下,我们用JavaScript的map()函数遍历numbers数组。我们为每个项返回一个<li>元素。最终我们将元素结果数组赋值给listItems:
const numbers=[1,2,3,4,5];
const listItems=numbers.map((number)=><li>{number}</li>);
我们将整个listItems数组放在<ul>元素中,渲染至DOM:
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
在CodePen上试试吧。
这些代码展示了1和5之间的一个数字列表。
基本的列表组
一般你想在一个组件中渲染列表
我们重构前面的例子成一个组件,这个组件接受数字数组和输出无序元素列表。
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。在创建元素列表时,“key”是必须包含的特殊字符串属性。在下一节我们将讨论它为什么很重要。
让我们在numbers.map()函数中为我们的列表项声明一个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')
);
在CodePen上试试吧。
键
键帮助React确定哪些项已经改变,添加或移除。把键赋给数组中元素给其一个有状态的标识。
const numbers=[1,2,3,4,5];
const listItems=numbers.map((number)=><li key={number.toString()}>{number}</li>);
挑选key的最好方法是使用一个唯一标识列表集合中项的字符串。大部分情况下,你可以从你的数据中用IDs作为Keys:
const todoItems=todos.map((todo)=><li key={todo.id}>{todo.text}</li>);
渲染的项没有IDs时,你只能用项指针作为key:
const todoItems=todos.map((todo,index)=>
//Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
We don`t recommend using indexes for keys if the items can reorder,as that would be slow.You may read an in-depth explanation about why keys are necessary if you`re interested.
如果项需要排序,我们不推荐用指针最为键,因为这样会慢。如果你感兴趣,可以阅读为什么键是必须的深入解读。
提取带键的组件
键只有在数组的上下文中才有意义。
例如,提取一个ListItem组件,应该保证在数组中<ListItem/>元素上的键而不是ListItem本身的根元素<li>上。
例子:错误的键使用
function ListItem(props){
const value=props.value;
return(
//Wrong ! There is no need to specify the key here:
<li key={value.toString()}>
{value}
</li>
);
}
function NumberList(props){
const numbers=props.numbers;
const listItems=numbers.map(
(number)=>
//Wrong ! The key should have been specified here:
<ListItem value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers=[1,2,3,4,5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
正确的键使用:
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')
);
在CodePen上试试吧。
最好的做法是在map()里调用需要的键。
在集合中键必须是唯一的
在数组中使用的键在集合中应该是唯一的。然而,不必是全局唯一。我们用两种不同的方法使用相同的键:
function Blog(props){
const sidebar=(
<ul>
{props.posts.map((post)=>
<li key={post.id}>
{post.title}
</li>
)}
</ul>
);
const content=props.posts.map((post)=>
<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')
);
在CodePen上试试吧。
Keys serve as a hint to React but they don`t get passed to your components.If you need the same value in your component,pass it explicitly as a prop with a different name:
键对React起暗示作用但是他们不能传递给组件。如果在组件中你需要相同的值,明确以不同的属性名传递。
const content=posts.map((post)=>
<Post
key={post.id}
id={post.id}
title={post.title} />
);
按照以上的例子,Post组件能够获取到props.id,不能获取props.key.
在JSX中植入map()
在以上例子中,我们声明一个分开的ListItems变量,在JSX中包含它:
function NumberList(props){
const numbers=props.numbers;
const listItems=numbers.map((number)=>
<ListItem key={number.toString()} value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
JSX允许用大括号包裹任何表达式,所以我们内联map()结果:
function NumberList(props){
const numbers=props.numbers;
return(
<ul>
{numbers.map((number)=>
<ListItem key={number.toString()} value={number} />
) }
</ul>
);
}
在CodePen上试试吧。
有时这样写代码更清晰,但是这种风格可能会被滥用。和用JavaScript一样,由你来决定是否值得提取一个变量以增强可读性。注意map()函数体如果嵌套太深,那就是提取组件的好时机到了。