首先,让咱们回顾一下如何在JavaScript中遍历lists。javascript
下面的代码,咱们使用map()
函数获取一个数字
数组,并将它们的值加倍。 咱们将map()
返回的新数组赋给变量doubled
并记录下来:java
const numbers = [1, 2, 3, 4, 5]; const doubled = numbers.map(item => item * 2); console.log(doubled); //=> [2, 4, 6, 8, 10]
上面的代码会在控制台打印[2, 4, 6, 8, 10]
。
在React中,将数组转换为元素集合
几乎和上面的代码是同样的。react
您能够本身一个建立元素集合,并使用花括号{}
将它们包含在JSX中。
下面,咱们使用Javascript map()
函数循环一个数字数组。 咱们为每一个item
返回一个<li>
元素。 最后,咱们将结果数组的元素赋给listItems
:数组
const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map(item => <li>{item}</li>);
咱们将整个listItems
数组包含在<ul>
元素中,并将其渲染到DOM:dom
ReactDOM.render( <ul>{listItems}</ul>, document.getElementById('root') )
此代码将会显示1到5之间的数字。ide
一般你会将List放在组件中。
咱们能够将前面的例子重构为接受数字数组的组件,并输出一个无序的元素列表。函数
import React from 'react'; import ReactDOM from 'react-dom'; function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map(item => <li>{item}</li>); return ( <ul>{listItems}</ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('root') );
当您运行此代码时,将会收到一条警告,
Each child in an array or iterator should have a unique "key" prop. Check the render method of "NumberList".
post
提示指出应该为列表的每一项提供一个属性key
。 “key”
是建立元素列表时须要包含的特殊字符串属性。 咱们将在下一节讨论为何它很重要。code
让咱们给numbers.map()
的列表项分配一个key
,并修复那个提示缺乏key
的问题。排序
import React from 'react'; import ReactDOM from 'react-dom'; function NumberList(props) { const numbers = props.numbers; - const listItems = numbers.map(item => <li>{item}</li>); + const listItems = numbers.map(item => <li key={item.toString()}>{item}</li>); return ( <ul>{listItems}</ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers}/>, document.getElementById('root') )
keys
帮助肯定哪些item
已更改,已添加或已删除。 应该给数组中的元素设置上key
属性,以便给元素一个稳定的身份:
const numbers =[1, 2, 3, 4, 5]; const listItems = numbers.map(item => <li key={item.toString()}> {item} </li> );
最好的方法是使用一个字符串
来选择key
,它是其兄弟之间一个列表项的惟一标识
。 一般,您会使用数据中的ID做为key:
const todoItems = todos.map(todo => <li key={todo.id}> {todo.text} </li> );
当您对已渲染的item没有稳定的ID时,您能够将项目index用做关键字:
const todoItems = todos.map((todo, index) => // 若是todo没有一个稳定的id,可使用这种方法 <li key={index}> {todo} </li> );
若是项目须要实现从新排序,咱们不建议为key使用索引,由于这将很慢。
Keys仅在循环时的上下文中有意义。
例如,若是您提取了一个ListItem
组件,则应该将该key保存在数组中的<ListItem />
元素上,而不是ListItem
自己的根<li>
元素上。
示例:key的错误用法
function ListItem(props) { const value = props.value; return ( <li key={value.toString()}> {value} </li> ); } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map(item => // 这是错误的,这里应该设置上key <ListItem value={item} /> ); return ( <ul>{listItems}</ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers}> />, document.getElementById('root') )
实例:key的正确用法
function ListItem(props) { // 这才是正确的,在这里不须要设置key return <li>{props.value}</li>; } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map(item => // 这才是正确的,在这里设置key <ListItem key={item.toString()} value={item} /> ); return ( <ul> {listItems} </ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('root') )
注意:map()
中的元素都须要属性key。在哪儿循环就在哪儿设置key。
数组中使用的key
在其兄弟组件之间应该是惟一的。 可是,它们不须要是全局惟一的。 当咱们生成两个不一样的数组时,咱们可使用相同的键:
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 zhangyatao', content: 'you\'re so handsome!'}, {id: 2, title: 'hi jiangyanyun', content: 'you\'re so beautiful!'} ]; ReactDOM.render( <Blog posts={posts} />, document.getElementById('root') )
key用来做为React的观察点,但它们不会传递给您的组件。 若是你须要在组件中使用相同的值,则使用不一样的名称显式地将它做为props传递:
const content = posts.map(post => <Post key={post.id} id={post.id} title={post.title} /> );
使用上面的示例,Post组件能够读取props.id
,但不能读取props.key
。
在上面的示例中,咱们声明了一个单独的listItems
变量并将其包含在JSX中:
function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map(item => <ListItem key={item.toString()} value={item} /> ); return ( <ul>{listItems}</ul> ); }
JSX容许在大括号中嵌入任何表达式,因此咱们能够内联map()
结果:
function NumberList(props) { const numbers = props.numbers; return ( <ul> {numbers.map(item => <ListItem key={item.toString()} value={item} /> )} </ul> ); }
这会让咱们的代码更清晰,这种风格能够被随意使用。
就像在JavaScript中,它是由你决定是否值得提取一个变量的可读性。
请记住,若是map()
主体嵌套太多层,那么它是抽出一个组件的好时机。