组件的生命周期(Life Cycle)包含三个阶段:挂载(Mounting)、更新(Updating)和卸载(Unmounting),在每个阶段都会有相应的回调方法(也叫钩子)可供选择,从而能更好的控制组件的行为。

一、挂载

  在这个阶段,组件会完成它的首次渲染,先执行初始化,再被挂载到真实的DOM中,其中依次调用的方法有constructor()、componentWillMount()、render()和componentDidMount()。除了render(),其他三个方法都只会运行一次。

1)constructor()

  在生命周期中,类的构造函数constructor()会率先被执行,用于初始化组件的状态、接收外部传递进来的数据、绑定成员方法的this指向等工作。

2)componentWillMount()

  componentWillMount()方法会运行在render()之前,它是渲染之前的回调函数。不过,由于在这个方法中执行的任务都能提前到constructor()中,因此实际项目中很少会用到它。

3)render()

  render()是在定义组件时必须声明的方法,它是一个无副作用的纯函数,可根据组件的props和state得到一个React元素、null或false等返回值,并且在render()方法中不能调用改变组件状态的this.setState()方法。注意,将元素渲染到页面DOM中的工作都由React负责,而不是render()方法。

4)componentDidMount()

  componentDidMount()方法会运行在render()之后,它是渲染之后的回调函数。此时组件已被挂载到页面中,可以执行DOM相关的操作,例如异步读取服务器中的数据并填充到组件中、调用jQuery代码等。

  下面的组件没有实际用途,仅仅是为了演示四个回调函数,其中componentWillMount()和componentDidMount()都成功调用了this.setState()方法。

class Btn extends React.Component {
constructor(props) {
super(props);
this.state = {
name: props.name
};
}
componentWillMount() {
this.setState({age: 28});
}
render() {
return <button>{this.state.name}</button>;
}
componentDidMount() {
$.post("server.php", {id:1}, json => {
this.setState({age: json.data.age});
}, "json");
}
}

二、更新

  引起组件更新(即重新渲染)的方式有三种,第一种是由父组件向下传递props(即调用父组件的render()方法)引起的更新,依次会调用五个方法:componentWillReceiveProps()、shouldComponentUpdate()、componentWillUpdate()、render()和componentDidUpdate()。第二种是通过改变自身state(即调用this.setState()方法)引起的更新,会忽略componentWillReceiveProps()方法,只执行四个回调函数。第三种是通过组件的forceUpdate()方法强制更新,只有后三个回调函数会被执行。在下面的组件中,定义了更新阶段的五个回调函数,并且点击按钮就会触发强制更新。

class Btn extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "strick"
};
}
dot() {
this.setState({name: "freedom"});
this.forceUpdate(); //强制更新
} componentWillReceiveProps(nextProps) { }
shouldComponentUpdate(nextProps, nextState) { return true; }
componentWillUpdate(nextProps, nextState) { }
render() {
return <button onClick={this.dot.bind(this)}>{this.state.name}</button>;
}
componentDidUpdate(prevProps, prevState) { }
}

1)componentWillReceiveProps()

  componentWillReceiveProps()方法常用于执行props更新后的逻辑,只有第一种更新方式才会调用它,该方法能接收一个名为nextProps的参数,表示父组件传递进来的新的props。当需要通过this.setState()方法将nextProps中的数据同步到内部状态时,要先比较nextProps和this.props中的值是否相同,再决定是否执行同步。由于在componentWillReceiveProps()中能调用this.setState()方法,因此为了避免进入一个死循环,在调用this.setState()方法更新组件时就不会触发它。

2)shouldComponentUpdate()

  shouldComponentUpdate()用于决定是否继续组件的更新,它能接收2个参数:nextProps和nextState,分别表示新的props和state,通过比较nextProps、nextState和组件当前的this.props、this.state能得出一个布尔类型的返回结果。当返回结果为false时,组件会停止更新,后续的componentWillUpdate()、render()和componentDidUpdate()也不会被执行。将这个方法使用恰当的话,能减少冗余的渲染,优化组件的性能。

3)componentWillUpdate()和componentDidUpdate()

  componentWillUpdate()和componentDidUpdate()分别运行在render()之前和之后,它们都能接收2个参数,前者提供更新后的props和state,后者提供更新前的props和state。在componentWillUpdate()中,不能调用this.setState()方法,以免发生不必要的死循环。

三、卸载

  当组件在从DOM中被卸载之前,会触发一个无参数的componentWillUnmount()方法。在该方法内适合做些清理的工作,例如清除定时器、移除多余的DOM元素等。下面演示了处理卸载的过程,限于篇幅省略了组件的构造函数和render()方法,只给出了关键代码。

class Btn extends React.Component {
componentWillUnmount() {
clearInterval(timeout);
}
}
var container = document.getElementById("container");
ReactDOM.render(<Btn>提交</Btn>, container);
ReactDOM.unmountComponentAtNode(container); //移除DOM中的组件

四、流程图

  接下来用一张总的流程图(如图5所示)来说明生命周期各个方法之间的关系,灰底的方法表示在其内部能调用this.setState()方法。

图5  组件生命周期流程图

五、过时和新增的回调方法

1)过时

  从React v16.3开始,有3个生命周期方法被标记为过时:componentWillMount()、componentWillReceiveProps()和componentWillUpdate(),目前它们仍然有效,但不建议在新代码中使用,官方为它们新增了一个以“UNSAFE_”作为前缀的别名。

2)新增

  React v16新增了两个生命周期方法,如下所列。

  (1)static getDerivedStateFromProps(nextProps, prevState)

  静态方法getDerivedStateFromProps()用来替代componentWillReceiveProps()。它在render()方法之前触发,包含两个参数:nextProps和prevState,分别表示新的props和旧的state。如果返回一个对象,那么更新state;如果返回null,那么就不更新state。

  (2)getSnapshotBeforeUpdate(prevProps, prevState)

  getSnapshotBeforeUpdate()方法用来替代componentWillUpdate()。它在最近一次渲染输出(即更新DOM)之前触发,包含两个参数:prevProps和prevState,分别表示旧的props和旧的state,返回值会成为componentDidUpdate()的第三个参数。

React躬行记(4)——生命周期的更多相关文章

  1. React躬行记(3)——组件

    组件(Component)由若干个React元素组成,包含属性.状态和生命周期等部分,满足独立.可复用.高内聚和低耦合等设计原则,每个React应用程序都是由一个个的组件搭建而成,即组成React应用 ...

  2. React躬行记(10)——高阶组件

    高阶组件(High Order Component,简称HOC)不是一个真的组件,而是一个没有副作用的纯函数,以组件作为参数,返回一个功能增强的新组件,在很多第三方库(例如Redux.Relay等)中 ...

  3. React躬行记(15)——React Hooks

    Hook(钩子)是React v16.8新引入的特性,能以钩子的形式为函数组件附加类组件的状态.生命周期等特性.React的类组件有难以拆分.测试,状态逻辑分散,难以复用等问题,虽然可以通过渲染属性( ...

  4. React躬行记(16)——React源码分析

    React可大致分为三部分:Core.Reconciler和Renderer,在阅读源码之前,首先需要搭建测试环境,为了方便起见,本文直接采用了网友搭建好的环境,React版本是16.8.6,与最新版 ...

  5. React躬行记(5)——React和DOM

    React实现了一套与浏览器无关的DOM系统,包括元素渲染.节点查询.事件处理等机制. 一.ReactDOM 自React v0.14开始,官方将与DOM相关的操作从React中剥离,组成单独的rea ...

  6. React躬行记(8)——样式

    由于React推崇组件模式,因此会要求HTML.CSS和JavaScript混合在一起,虽然这与过去的关注点分离正好相反,但是更有利于组件之间的隔离.React已将HTML用JSX封装,而对CSS只进 ...

  7. React躬行记(2)——JSX

    JSX既不是字符串,也不是HTML,而是一种类似XML,用于描述用户界面的JavaScript扩展语法,如下代码所示.在使用JSX时,为了避免自动插入分号时出现问题,推荐在其最外层用圆括号包裹,并且必 ...

  8. React躬行记(6)——事件

    React在原生事件的基础上,重新设计了一套跨浏览器的合成事件(SyntheticEvent),在事件传播.注册方式.事件对象等多个方面都做了特别的处理. 一.注册事件 合成事件采用声明式的注册方式, ...

  9. React躬行记(7)——表单

    表单元素是一类拥有内部状态的元素,这些状态由其自身维护,通过这类元素可让用户与Web应用进行交互.HTML中的表单元素(例如<input>.<select>和<radio ...

随机推荐

  1. android中滑动SQLite数据库分页加载

    今天用到了android中滑动SQlit数据库分页加载技术,写了个测试工程,将代码贴出来和大家交流一下: MainActivity package com.example.testscrollsqli ...

  2. Redis 宝典 | 基础、高级特性与性能调优

    转载:Redis 宝典 | 基础.高级特性与性能调优 本文由 DevOpsDays 本文由简书作者kelgon供稿,高效运维社区致力于陪伴您的职业生涯,与您一起愉快的成长.     作者:kelgon ...

  3. Android系统联系人全特效实现(上),分组导航和挤压动画

    记得在我刚接触Android的时候对系统联系人中的特效很感兴趣,它会根据手机中联系人姓氏的首字母进行分组,并在界面的最顶端始终显示一个当前的分组.如下图所示: 最让我感兴趣的是,当后一个分组和前一个分 ...

  4. 陈硕 - Linux 多线程服务端编程 - muduo 网络库作者

    http://chenshuo.com/book/ Muduo网络库源码分析(一) EventLoop事件循环(Poller和Channel)http://blog.csdn.net/nk_test/ ...

  5. HDOJ 5090 Game with Pearls 二分图匹配

    简单的二分图匹配: 每个位置可以边到这些数字甚至可以边 Game with Pearls Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: ...

  6. 在WPF中添加3D特性

    原文:在WPF中添加3D特性 35.4  在WPF中添加3D特性 本节介绍WPF中的3D特性,其中包含了开始使用该特性的信息. 提示: WPF中的3D特性在System.Windows.Media.M ...

  7. WPF(C#)中Bitmap与BitmapImage相互转换

    原文:WPF(C#)中Bitmap与BitmapImage相互转换 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/wangshubo1989/art ...

  8. window下nodejs爬取gb2312网页出现乱码的解决方案

     发布于 2012-8-22 18:15  5230 次浏览  最后一次编辑是 2013-2-18 22:31 linux环境下,我们可以通过 iconv 这个C++模块来处理Node.JS不支持的字 ...

  9. AR研究-Demo集

    原文:AR研究-Demo集        之前研究了图像处理.图像识别及AR 等相关技术,下载了很多开源源码进行学习和尝试引用,包括c++.c#.Opengl.Emgu. Aforge.OpenCV. ...

  10. Form submit

    方法1:使用form onsubmit标签 return XXX()方法 <!--onsubmit--> <form id="formid" name=" ...