列表数据在前端很是常见,咱们常常要处理这种类型的数据,例如文章列表、评论列表、用户列表…一个前端工程师几乎天天都须要跟列表数据打交道。html
React.js 固然也容许咱们处理列表数据,但在使用 React.js 处理列表数据的时候,须要掌握一些规则。咱们这一节会专门讨论这方面的知识。前端
假设如今咱们有这么一个用户列表数据,存放在一个数组当中:数组
const users = [ { username: 'Jerry', age: 21, gender: 'male' }, { username: 'Tomy', age: 22, gender: 'male' }, { username: 'Lily', age: 19, gender: 'female' }, { username: 'Lucy', age: 20, gender: 'female' } ]
若是如今要把这个数组里面的数据渲染页面上要怎么作?开始以前要补充一个知识。以前说过 JSX 的表达式插入 {}
里面能够听任何数据,若是咱们往 {}
里面放一个存放 JSX 元素的数组会怎么样?浏览器
... class Index extends Component { render () { return ( <div> {[ <span>React.js </span>, <span>is </span>, <span>good</span> ]} </div> ) } } ReactDOM.render( <Index />, document.getElementById('root') )
咱们往 JSX 里面塞了一个数组,这个数组里面放了一些 JSX 元素(其实就是 JavaScript 对象)。到浏览器中,你在页面上会看到:前端工程师
审查一下元素,看看会发现什么:函数
React.js 把插入表达式数组里面的每个 JSX 元素一个个罗列下来,渲染到页面上。因此这里有个关键点:若是你往 {}
放一个数组,React.js 会帮你把数组里面一个个元素罗列而且渲染出来。优化
知道这一点之后你就能够知道怎么用循环把元素渲染到页面上:循环上面用户数组里面的每个用户,为每一个用户数据构建一个 JSX,而后把 JSX 放到一个新的数组里面,再把新的数组插入 render
方法的 JSX 里面。看看代码怎么写:this
const users = [ { username: 'Jerry', age: 21, gender: 'male' }, { username: 'Tomy', age: 22, gender: 'male' }, { username: 'Lily', age: 19, gender: 'female' }, { username: 'Lucy', age: 20, gender: 'female' } ] class Index extends Component { render () { const usersElements = [] // 保存每一个用户渲染之后 JSX 的数组 for (let user of users) { usersElements.push( // 循环每一个用户,构建 JSX,push 到数组中 <div> <div>姓名:{user.username}</div> <div>年龄:{user.age}</div> <div>性别:{user.gender}</div> <hr /> </div> ) } return ( <div>{usersElements}</div> ) } } ReactDOM.render( <Index />, document.getElementById('root') )
这里用了一个新的数组 usersElements
,而后循环 users
数组,为每一个 user
构建一个 JSX 结构,而后 push 到 usersElements
中。而后直接用表达式插入,把这个 userElements
插到 return 的 JSX 当中。由于 React.js 会自动化帮咱们把数组当中的 JSX 罗列渲染出来,因此能够看到页面上显示:spa
但咱们通常不会手动写循环来构建列表的 JSX 结构,能够直接用 ES6 自带的 map
(不了解 map
函数的同窗能够先了解相关的知识再来回顾这里),代码能够简化成:code
class Index extends Component { render () { return ( <div> {users.map((user) => { return ( <div> <div>姓名:{user.username}</div> <div>年龄:{user.age}</div> <div>性别:{user.gender}</div> <hr /> </div> ) })} </div> ) } }
这样的模式在 JavaScript 中很是常见,通常来讲,在 React.js 处理列表就是用 map
来处理、渲染的。如今进一步把渲染单独一个用户的结构抽离出来做为一个组件,继续优化代码:
const users = [ { username: 'Jerry', age: 21, gender: 'male' }, { username: 'Tomy', age: 22, gender: 'male' }, { username: 'Lily', age: 19, gender: 'female' }, { username: 'Lucy', age: 20, gender: 'female' } ] class User extends Component { render () { const { user } = this.props return ( <div> <div>姓名:{user.username}</div> <div>年龄:{user.age}</div> <div>性别:{user.gender}</div> <hr /> </div> ) } } class Index extends Component { render () { return ( <div> {users.map((user) => <User user={user} />)} </div> ) } } ReactDOM.render( <Index />, document.getElementById('root') )
这里把负责展现用户数据的 JSX 结构抽离成一个组件 User
,而且经过 props
把 user
数据做为组件的配置参数传进去;这样改写 Index
就很是清晰了,看一眼就知道负责渲染 users
列表,而用的组件是 User
。
如今代码运做正常,好像没什么问题。打开控制台看看:
React.js 报错了。若是须要详细解释这里报错的缘由,估计要单独写半本书。但能够简单解释一下。
React.js 的是很是高效的,它高效依赖于所谓的 Virtual-DOM 策略。简单来讲,能复用的话 React.js 就会尽可能复用,没有必要的话绝对不碰 DOM。对于列表元素来讲也是这样,可是处理列表元素的复用性会有一个问题:元素可能会在一个列表中改变位置。例如:
<div>a</div> <div>b</div> <div>c</div>
假设页面上有这么3个列表元素,如今改变一下位置:
<div>a</div> <div>c</div> <div>b</div>
c
和 b
的位置互换了。但其实 React.js 只须要交换一下 DOM 位置就好了,可是它并不知道其实咱们只是改变了元素的位置,因此它会从新渲染后面两个元素(再执行 Virtual-DOM 策略),这样会大大增长 DOM 操做。但若是给每一个元素加上惟一的标识,React.js 就能够知道这两个元素只是交换了位置:
<div key='a'>a</div> <div key='b'>b</div> <div key='c'>c</div>
这样 React.js 就简单的经过 key
来判断出来,这两个列表元素只是交换了位置,能够尽可能复用元素内部的结构。
这里没听懂没有关系,后面有机会会继续讲解这部份内容。如今只须要记住一个简单的规则:对于用表达式套数组罗列到页面上的元素,都要为每一个元素加上 key
属性,这个 key
必须是每一个元素惟一的标识。通常来讲,key
的值能够直接后台数据返回的 id
,由于后台的 id
都是惟一的。
在上面的例子当中,每一个 user
没有 id
能够用,能够直接用循环计数器 i
做为 key
:
... class Index extends Component { render () { return ( <div> {users.map((user, i) => <User key={i} user={user} />)} </div> ) } } ...
再看看,控制台已经没有错误信息了。但这是很差的作法,这只是掩耳盗铃(具体缘由你们能够本身思考一下)。记住一点:在实际项目当中,若是你的数据顺序可能发生变化,标准作法是最好是后台数据返回的 id
做为列表元素的 key
。