React.js 小书 Lesson19 - 挂载阶段的组件生命周期(二)
- 作者:胡子大哈
- 原文链接:http://huziketang.com/books/react/lesson19
- 转载请注明出处,保留原文链接和作者信息。
这一节我们来讨论一下对于一个组件来说,constructor 、componentWillMount、componentDidMount、componentWillUnmount 这几个方法在一个组件的出生到死亡的过程里面起了什么样的作用。
一般来说,所有关于组件自身的状态的初始化工作都会放在 constructor 里面去做。你会发现本书所有组件的 state 的初始化工作都是放在 constructor 里面的。假设我们现在在做一个时钟应用:

我们会在 constructor 里面初始化 state.date,当然现在页面还是静态的,等下一会让时间动起来。
class Clock extends Component {
constructor () {
super()
this.state = {
date: new Date()
}
}
render () {
return (
<div>
<h1>
<p>现在的时间是</p>
{this.state.date.toLocaleTimeString()}
</h1>
</div>
)
}
}
一些组件启动的动作,包括像 Ajax 数据的拉取操作、一些定时器的启动等,就可以放在 componentWillMount 里面进行,例如 Ajax:
...
componentWillMount () {
ajax.get('http://json-api.com/user', (userData) => {
this.setState({ userData })
})
}
...
当然在我们这个例子里面是定时器的启动,我们给 Clock 启动定时器:
class Clock extends Component {
constructor () {
super()
this.state = {
date: new Date()
}
}
componentWillMount () {
this.timer = setInterval(() => {
this.setState({ date: new Date() })
}, 1000)
}
...
}
我们在 componentWillMount 中用 setInterval 启动了一个定时器:每隔 1 秒更新中的 state.date,这样页面就可以动起来了。我们用一个 Index 把它用起来,并且插入页面:
class Index extends Component {
render () {
return (
<div>
<Clock />
</div>
)
}
}
ReactDOM.render(
<Index />,
document.getElementById('root')
)
像上一节那样,我们修改这个 Index 让这个时钟可以隐藏或者显示:
class Index extends Component {
constructor () {
super()
this.state = { isShowClock: true }
}
handleShowOrHide () {
this.setState({
isShowClock: !this.state.isShowClock
})
}
render () {
return (
<div>
{this.state.isShowClock ? <Clock /> : null }
<button onClick={this.handleShowOrHide.bind(this)}>
显示或隐藏时钟
</button>
</div>
)
}
}
现在页面上有个按钮可以显示或者隐藏时钟。你试一下显示或者隐藏时钟,虽然页面上看起来功能都正常,在控制台你会发现报错了:

这是因为,当时钟隐藏的时候,我们并没有清除定时器。时钟隐藏的时候,定时器的回调函数还在不停地尝试 setState,由于 setState 只能在已经挂载或者正在挂载的组件上调用,所以 React.js 开始疯狂报错。
多次的隐藏和显示会让 React.js 重新构造和销毁 Clock 组件,每次构造都会重新构建一个定时器。而销毁组件的时候没有清除定时器,所以你看到报错会越来越多。而且因为 JavaScript 的闭包特性,这样会导致严重的内存泄漏。
这时候componentWillUnmount 就可以派上用场了,它的作用就是在组件销毁的时候,做这种清场的工作。例如清除该组件的定时器和其他的数据清理工作。我们给 Clock 添加 componentWillUnmount,在组件销毁的时候清除该组件的定时器:
...
componentWillUnmount () {
clearInterval(this.timer)
}
...
这时候就没有错误了。
总结
我们一般会把组件的 state 的初始化工作放在 constructor 里面去做;在 componentWillMount 进行组件的启动工作,例如 Ajax 数据拉取、定时器的启动;组件从页面上销毁的时候,有时候需要一些数据的清理,例如定时器的清理,就会放在 componentWillUnmount 里面去做。
说一下本节没有提到的 componentDidMount 。一般来说,有些组件的启动工作是依赖 DOM 的,例如动画的启动,而 componentWillMount 的时候组件还没挂载完成,所以没法进行这些启动工作,这时候就可以把这些操作放在 componentDidMount 当中。componentDidMount 的具体使用我们会在接下来的章节当中结合 DOM 来讲。
课后练习
因为第三方评论工具有问题,对本章节有任何疑问的朋友可以移步到 React.js 小书的论坛 发帖,我会回答大家的疑问。
React.js 小书 Lesson19 - 挂载阶段的组件生命周期(二)的更多相关文章
- React.js 小书 Lesson18 - 挂载阶段的组件生命周期(一)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson18 转载请注明出处,保留原文链接和作者信息. 我们在讲解 JSX 的章节中提到,下面的代码: ...
- React.js 小书 Lesson20 - 更新阶段的组件生命周期
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson20 转载请注明出处,保留原文链接和作者信息. 从之前的章节我们了解到,组件的挂载指的是将组件 ...
- React.js 小书 Lesson15 - 实战分析:评论功能(二)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson15 转载请注明出处,保留原文链接和作者信息. 上一节我们构建了基本的代码框架,现在开始完善其 ...
- 【React.js小书】动手实现 React-redux(五):Provider - 方志
我们要把 context 相关的代码从所有业务组件中清除出去,现在的代码里面还有一个地方是被污染的.那就是 src/index.js 里面的 Index: 1234567891011121314151 ...
- React.js 小书介绍
React.js 小书 Github 关于作者 这是一本关于 React.js 的小书. 因为工作中一直在使用 React.js,也一直以来想总结一下自己关于 React.js 的一些知识.经验.于是 ...
- React.js 小书 Lesson16 - 实战分析:评论功能(三)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson16 转载请注明出处,保留原文链接和作者信息. 接下来的代码比较顺理成章了.修改 Commen ...
- 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 转载请注明出处,保留原文链接和作者信息. (本文未审核) 持久化评论 同样地,可以通过类 ...
随机推荐
- CentOS 傻瓜式部署uWSGI + nginx + flask
交代背景 这篇帖子是为了提供我自己的July Novel站点的小说数据支撑.解决分布式部署爬虫程序的繁琐过程,由于本人对shell编程并不熟悉,故而先逐步记录操作步骤,通过以下操作达到节省时间的方式. ...
- ref和out params
ref和out都对函数参数采用引用传递形式——不管是值类型参数还是引用类型参数,并且定义函数和调用函数时都必须显示生命该参数为 ref/out形式.两者都可以使函数传回多个结果. ref 类似于 PH ...
- php面试题汇集2
1.实现中文字符串截取无乱码方法 开启mbstring扩展,然后自定义函数: <?php header('content-Type:text/html:charset=utf-8'); func ...
- Python——深拷贝和浅拷贝
深拷贝.浅拷贝 1. 浅拷贝 浅拷贝是对于一个对象的顶层拷贝 import copy a = [[1, 2], 3] b = copy.copy(a) print(id(a)) print(id(b) ...
- UIView中的tintColor和renderingMode
tintColor 每一个view都有一个tintcolor,类似于魔法色,实现类似于换肤的效果. 每一个view的subview都集成view的tintcolor,当然subview可以指定自己的t ...
- [译文]casperjs 的API-casper模块
Casper class: 可以通过这个模块的create()方法来获取这个模块的一个实例,这是最容易的: var casper = require('casper').create(); 我们也可以 ...
- es去重查询
{ "query": { "bool": { "must": ...
- (STM32F4) Timer 基本操作
Timer (計時器) 就是慢慢數時間,在timer內部有一個計數器. 而計數器會數到Register的value當數值數到設定值Timer就會發起IRQ 而程式就會轉跳到中斷向量裡頭去執行想要做的事 ...
- 海思hi35xx 开发学习(1):海思媒体处理平台架构
处理平台架构图: 主要分为: 视频输入(VI):VI 模块捕获视频图像,可对其做剪切.去噪等处理,并输出多路不同分辨率的图像数据. 视频处理(VPSS):VPSS 模块接收 VI 和解码模块发送过来的 ...
- pip报failed to create process
使用pip命令的时候报failed to create process 1.错误提示窗口如下图 2.报这个错误的原因,是因为你改动了python的目录名称或位置.因为,我的电脑是安装了anaconda ...