组件的生命周期(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. windows mysql5.7 InnoDB 通过frm与ibd对数据进行恢复

    参考:https://www.jianshu.com/p/50a2e13cd5cf 安装MySQL Utilities 下载地址:https://dev.mysql.com/downloads/uti ...

  2. 微信公众平台通用接口API指南

    微信公众平台 通用接口 消息接口 开发模式 作者:方倍工作室原文:http://www.doucube.com/index.php?m=Article&a=show&id=5 微信公众 ...

  3. Leetcode 100 Same Tree 二叉树

    就是判断两棵树的值和结构是否相同 注意:要判断是否所有的树节点是否为NULL /** * Definition for a binary tree node. * struct TreeNode { ...

  4. 分位数(quantiles)、Z-score 与 F-score

    0. 分位数(quantiles) 因为累计分布函数(cdf,F−1)是单调增函数,因此其有反函数,不妨记为 F−1. 其真实的含义在于,如果 F 是 X 的 cdf,则 F−1(α) 的函数值为: ...

  5. 键盘各键对应的编码值(key code)

    原文:键盘各键对应的编码值(key code) 来源:http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes ...

  6. Matlab随笔之矩阵入门知识

    原文:Matlab随笔之矩阵入门知识 直接输入法创建矩阵 – 矩阵的所有元素必须放在方括号“[ ]”内: – 矩阵列元素之间必须用逗号“,”或空格隔开,每行必须用“;”隔开 – 矩阵元素可以是任何不含 ...

  7. Android Ant 和 Gradle 包装工艺和效率控制

    一个.Ant 包:(下载ant.配置环境变量不说) 1.进入命令行模式,并切换到项目文件夹,运行例如以下命令为ADT创建的项目加入ant build支持: android update project ...

  8. maven私服nexus安装

    maven私服nexus安装 1.nexus特性 1.1.nexus私服实际上是一个javaEE的web 系统 1.2.作用:用来管理一个公司所有的jar包,实现项目jar包的版本统一 1.3.jar ...

  9. Matlab随笔之模拟退火算法

    问题描述: 我方有一个基地,经度和纬度为( 70,40).假设我方飞机的速度为 1000 公里/小时. 我方派一架飞机从基地出发,侦察完敌方所有目标,再返回原来的基地.在敌方每一目 标点的侦察时间不计 ...

  10. html5 命运之轮生产

    码,如以下: <%@ page language="java" contentType="text/html; charset=UTF-8" pageEn ...