React.js 小书 Lesson13 - 渲染列表数据
- 作者:胡子大哈
- 原文链接:http://huziketang.com/books/react/lesson13
- 转载请注明出处,保留原文链接和作者信息。
列表数据在前端非常常见,我们经常要处理这种类型的数据,例如文章列表、评论列表、用户列表…一个前端工程师几乎每天都需要跟列表数据打交道。
React.js 当然也允许我们处理列表数据,但在使用 React.js 处理列表数据的时候,需要掌握一些规则。我们这一节会专门讨论这方面的知识。
渲染存放 JSX 元素的数组
假设现在我们有这么一个用户列表数据,存放在一个数组当中:
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 会帮你把数组里面一个个元素罗列并且渲染出来。
使用 map 渲染列表数据
知道这一点以后你就可以知道怎么用循环把元素渲染到页面上:循环上面用户数组里面的每一个用户,为每个用户数据构建一个 JSX,然后把 JSX 放到一个新的数组里面,再把新的数组插入 render
方法的 JSX 里面。看看代码怎么写:
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 罗列渲染出来,所以可以看到页面上显示:
但我们一般不会手动写循环来构建列表的 JSX 结构,可以直接用 ES6 自带的 map
(不了解 map
函数的同学可以先了解相关的知识再来回顾这里),代码可以简化成:
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
。
key! key! key!
现在代码运作正常,好像没什么问题。打开控制台看看:
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
。
课后练习
因为第三方评论工具有问题,对本章节有任何疑问的朋友可以移步到 React.js 小书的论坛 发帖,我会回答大家的疑问。
React.js 小书 Lesson13 - 渲染列表数据的更多相关文章
- 【React.js小书】动手实现 React-redux(五):Provider - 方志
我们要把 context 相关的代码从所有业务组件中清除出去,现在的代码里面还有一个地方是被污染的.那就是 src/index.js 里面的 Index: 1234567891011121314151 ...
- React.js 小书介绍
React.js 小书 Github 关于作者 这是一本关于 React.js 的小书. 因为工作中一直在使用 React.js,也一直以来想总结一下自己关于 React.js 的一些知识.经验.于是 ...
- React.js小书总结
(迁移自旧博客2017 08 27) 第一阶段 react的组件相当于MVC里面的View. react.js 将帮助我们将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合.嵌套,就成 ...
- React.js 小书 Lesson25 - 实战分析:评论功能(四)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson25 转载请注明出处,保留原文链接和作者信息. (本文未审核) 目前为止,第二阶段知识已经基本 ...
- React.js 小书 Lesson26 - 实战分析:评论功能(五)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson26 转载请注明出处,保留原文链接和作者信息. (本文未审核) 持久化评论 同样地,可以通过类 ...
- React.js 小书 Lesson16 - 实战分析:评论功能(三)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson16 转载请注明出处,保留原文链接和作者信息. 接下来的代码比较顺理成章了.修改 Commen ...
- React.js 小书 Lesson15 - 实战分析:评论功能(二)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson15 转载请注明出处,保留原文链接和作者信息. 上一节我们构建了基本的代码框架,现在开始完善其 ...
- React.js 小书 Lesson23 - dangerouslySetHTML 和 style 属性
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson23 转载请注明出处,保留原文链接和作者信息. 这一节我们来补充两个之前没有提到的属性,但是在 ...
- React.js 小书 Lesson17 - 前端应用状态管理 —— 状态提升
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson17 转载请注明出处,保留原文链接和作者信息. 上一个评论功能的案例中,可能会有些同学会对一个 ...
随机推荐
- 将.net core 发布到Linux上的一些坑
目前遇到的,之后遇到再加 1.时间格式要用.ToString("yyyy-MM-dd HH:mm:ss"); 2.文件路径要用Path.Combine(),IHostingEnvi ...
- 201621123012 《Java程序设计》第6周学习总结
1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰 ...
- SVN Unable to connect to a repository at URL 不知道这样的主机: 问题解决
工具是eclipse Maven ,搭建好项目的框架后上传SVN出现如下错误: 不知道这样的主机. svn: Unable to connect to a repository at URL 'ht ...
- jwt-dotnet使用示例
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- ansible基本模块-command
- angularJs路由的使用
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- bootstrap Table从零开始
本文博主将从零开始,一步一步的告诉大家如何在前端用bootstrap Table插件展示一个表格 首先,要下载bootstrap Table插件所必须的js,地址:https://github.c ...
- Vue keep-alive 组件.
如果不用 webpack , 那么 name 就是 vue.component(name) 这个 name 就是 export default { name:"index"} 的那 ...
- ESP8266使用详解
[From] http://www.cnblogs.com/yangfengwu/p/5205570.html 用的这款 各引脚功能:来至厂家提供的资料 GPIO0 默认是工作模式(不接线).如果接了 ...
- eclipse+maven远程(自动)部署web项目到tomcat
[转自] http://blog.csdn.net/dhmpgt/article/details/11197995 eclipse集成maven后可以用maven命令把web项目自动部署到tomcat ...