ReactNative进阶(十六):React-Native 组件生命周期
概述
所谓生命周期,就是一个对象从开始生成到最后消亡所经历的状态,理解生命周期,是合理开发的关键。RN 组件的生命周期整理如下图:

如图,可以把组件生命周期大致分为三个阶段:
第一阶段:是组件第一次绘制阶段,如图中的上面虚线框内,在这里完成了组件的加载和初始化;
第二阶段:是组件在运行和交互阶段,如图中左下角虚线框,这个阶段组件可以处理用户交互,或者接收事件更新界面;
第三阶段:是组件卸载消亡的阶段,如图中右下角的虚线框中,这里做一些组件的清理工作。
一、组件的生命周期
组件的生命周期一般分为 4 个阶段:。下面对各个阶段分别进行介绍。
1.1 创建阶段
该阶段主要发生在创建组件类的时候,在这个阶段中会初始化组件的属性类型和默认属性。通常会将固定的内容放在这个过程中进行初始化和赋值。在 中统一使用 成员来实现。
static defaultProps = {
autoPlay: false,
maxLoop: 10,
};
1.2 实例化阶段
该阶段主要发生在实例化组件类的时候,也就是该组件类被调用的时候触发。这个阶段会触发一系列的流程,按执行顺序如下:
:构造函数,这里主要对组件的一些状态进行初始化。
:准备加载组件,可以在这里做一些业务初始化操作,或者设置组件状态。
:生成页面需要的 结构,并返回该结构。
:组件加载成功并被成功渲染出来后执行。一般会将网络请求等加载数据的操作放在这里进行,保证不会出现 上的错误。
1.3 运行(更新)阶段
该阶段主要发生在用户操作之后或者父组件有更新的时候,此时会根据用户的操作行为进行相应的页面结构调整。这个阶段也会触发一系列的流程,按执行顺序如下:
:当组件接收到新的 时,会触发该函数。在该函数中,通常可以调用 方法来完成对 的修改。
:该方法用来拦截新的 或 ,然后根据事先设定好的判断逻辑,做出最后要不要更新组件的决定。
:当上面的方法拦截返回 的时候,就可以在该方法中做一些更新之前的操作。
:根据一系列的 算法,生成需要更新的 数据。(注意:在 中最好只做数据和模板的组合,不应进行 等逻辑的修改,这样组件结构会更加清晰)
:该方法在组件的更新已经同步到 中去后触发,常在该方法中做 操作。
1.4 销毁阶段
该阶段主要在组件消亡的时候触发。
:当组件要被从界面上移除时就会调用。可以在这个函数中做一些相关的清理工作,例如取消计时器、网络请求等。
二、生命周期函数详细介绍
下面来详细介绍生命周期中的各回调函数。
constructor
(1)函数原型
constructor(props)
(2)基本介绍它是组件的构造函数。它的第一个语句必须是 。构造函数将在组件被加载前最先调用,并且仅调用一次。
(3)常见用途构造函数最大的作用,就是在这里定义状态机变量。
getDefaultProps
在组件创建之前,会先调用 ,全局调用一次。严格来说,这不是组件生命周期的一部分。在组件被创建并加载后,首先调用 ,来初始化组件的状态。
componentWillMount
然后,准备加载组件,会调用 ,其原型如下:
void componentWillMount()
这个函数调用时机是在组件创建,并初始化状态之后,在第一次绘制 之前。
(2)基本介绍
在组件的生命周期中,这个函数只会被执行一次。
这个函数无参数并且不需要任何返回值。
它在初始渲染( 函数被 框架调用执行)前被执行,当它执行完后, 函数会马上被 框架调用执行。注意:如果在这个函数里调用 函数改变了某些状态机变量的值, 框架不会执行渲染操作,而是等待这个函数执行完成后再执行初始渲染。
如果子组件也有 函数,它会在父组件的 函数之后被调用。
(3)常见用途如果我们需要从本地存储中读取数据用于显示,那么在这个函数里进行读取是一个很好的时机。可以在这里做一些业务初始化操作,也可以设置组件状态。
render
(1)函数原型
render()
(2)基本介绍 是一个组件必须有的方法,用于界面渲染。这个函数无参数,返回 或者其他组件来构成 。
注意:只能返回一个顶级元素。
componentDidMount
在组件第一次绘制之后,会调用 ,通知组件已经加载完成。函数原型如下:
void componentDidMount()
这个函数调用的时候,其 已经构建完成,你可以在这个函数开始获取其中的元素或者子组件。需要注意的是,RN 框架是先调用子组件的 ,然后调用父组件的函数。从这个函数开始,就可以和 JS 其他框架交互了,例如设置计时 或者 ,或者发起网络请求。这个函数也是只被调用一次。这个函数之后,就进入了稳定运行状态,等待事件触发。
(2)基本介绍
在组件的生命周期中,这个函数只会被执行一次。
这个函数无参数并且不需要任何返回值。
它在初始渲染执行完成后会马上被调用。在组件生命周期的这个时间点之后,开发者可以通过子组件的引用来访问、操作任何子组件。
如果子组件也有 函数,它会在父组件的 函数之前被调用。
(3)常见用途如果 应用需要在程序启动并显示初始界面后从网络侧获取数据,那么把从网络侧获取数据的代码放在这个函数里是一个不错的选择。
componentWillReceiveProps
如果组件收到新的属性(),就会调用 ,其原型如下:
void componentWillReceiveProps(
object nextProps
)
输入参数 是即将被设置的属性,旧的属性还是可以通过 来获取。在这个回调函数里面,可以根据属性变化,通过调用 来更新组件状态,这里调用更新状态是安全的,并不会触发额外的 调用。如下:
componentWillReceiveProps: function(nextProps) {
this.setState({
likesIncreasing: nextProps.likeCount > this.props.likeCount
});
}
(2)基本介绍
组件的初始渲染执行完成后,当组件接收到新的 时,这个函数将被调用。
这个函数不需要返回值。接收一个 参数, 里是新的 。
如果新的 会导致界面重新渲染,这个函数将在渲染前被执行。在这个函数中,老的 可以通过 访问,新的 在传入的 中。
如果在这个函数中通过调用 函数改变某些状态机变量的值, 框架不会执行对这些状态机变量改变的渲染,而是等 函数执行完成后一起渲染。
注意: 当 初次被渲染时, 函数并不会被触发,这种机制是故意设计的。
shouldComponentUpdate
当组件接收到新的属性和状态改变,都会触发调用 ,函数原型如下:
boolean shouldComponentUpdate(
object nextProps, object nextState
)
输入参数 和上面的 函数一样, 表示组件即将更新的状态值。这个函数的返回值决定是否需要更新组件,如果 表示需要更新,继续走后面的更新流程。否者,则不更新,直接进入等待状态。
默认情况下,这个函数永远返回 用来保证数据变化的时候 能够同步更新。在大型项目中,可以自己重载这个函数,通过检查变化前后属性和状态,来决定 是否需要更新,有效提高应用性能。
(2)基本介绍
组件初始渲染执行完成后,当组件接收到新的 或者 时这个函数将被调用。
该函数接收两个 参数,其中第一个是新的 ,第二个是新的 。
该函数需要返回一个布尔值,告诉 框架针对这次改变,是否需要重新渲染本组件。默认返回 。如果此函数返回 , 将不会重新渲染本组件,相应的,该组件的 和 函数也不会被调用。
(3)常见用途这个函数常常用来阻止不必要的重新渲染,提高 应用程序性能。比如我们可以在该函数中比较新老版本的 和 ,判断是否需要进行重新渲染。下面是一个简单的使用样例:
shouldComponentUpdate(nextProps, nextState) {
if(this.state.inputedNum.length < 3) return false;
return true;
}
componentWillUpdate
如果组件状态或者属性改变,并且上面的 返回为 ,就会开始准更新组件,并调用 ,其函数原型如下:
void componentWillUpdate(
object nextProps, object nextState
)
输入参数与 一样,在这个回调中,可以做一些在更新界面之前要做的事情。需要特别注意的是,在这个函数里面,不能使用 来修改状态。这个函数调用之后,就会把 和 分别设置到 和 中。紧接着这个函数,就会调用 来更新界面。
(2)基本介绍
组件初始渲染执行完成后, 框架在重新渲染该组件前会调用这个函数。
该函数不需要返回值,接收两个 参数,其中第一个是新的 ,第二个是新的 。
可以在这个函数中为即将发生的重新渲染做一些准备工作,但不能在这个函数中通过 再次改变状态机变量的值。如果需要改变,则在 函数中进行改变。
componentDidUpdate
调用了 更新完成界面之后,会调用 来得到通知,其函数原型如下:
void componentDidUpdate(
object prevProps, object prevState
)
到这里,就完成了属性和状态的更新,此函数的输入参数变成了 和 。
基本介绍
组件初始渲染执行完成后, 框架在重新渲染该组件完成后会调用这个函数。
该函数不需要返回值,接收两个 参数,其中第一个是渲染前的 ,第二个是渲染前的 。
componentWillUnmount
当组件要被从界面上移除的时候,就会调用 ,其函数原型如下:
void componentWillUnmount()
在这个函数中,可以做一些组件相关的清理工作,例如取消计时器、网络请求等。
(2)基本介绍
在组件被卸载前,这个函数将被执行。
这个函数没有参数,也没不需要返回值。
(3)常见用途如果组件申请了某些资源或者订阅了某些消息,那么需要在这个函数中释放资源,取消订阅。
三、完整样例
下面通过一个简单的文本显示组件,来演示组件各个环节的运作流程。同时这里把组件整个生命周期中所有会触发的方法罗列出来。
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
TextInput,
View,
Text,
Clipboard
} from 'react-native';
export default class Main extends Component {
//构造函数
constructor(props) {
super(props);
console.log("constructor");
//初始化状态值
this.state = {message: "欢迎访问 hangge.com"}
}
//准备加载组件
componentWillMount() {
console.log("componentWillMount");
}
//渲染界面
render() {
console.log("render");
return (
{this.state.message}
);
}
//组件加载成功并渲染出来
componentDidMount() {
console.log("componentDidMount");
}
//组件接收到新的 props 时触发
componentWillReceiveProps(nextProps) {
console.log("componentWillReceiveProps");
}
//决定是否需要更新组件
shouldComponentUpdate(nextProps, nextState) {
console.log("shouldComponentUpdate");
}
//组件重新渲染前会调用
componentWillUpdate(nextProps, nextState) {
console.log("componentWillUpdate");
}
//组件重新渲染后会调用
componentDidUpdate(prevProps, prevState) {
console.log("componentDidUpdate");
}
//组件被卸载前会调用
componentWillUnmount() {
console.log("componentWillUnmount");
}
}
const styles = StyleSheet.create({
container:{
flex:1,
marginTop:40,
alignItems:'center',
},
info:{
fontSize:20,
},
});
AppRegistry.registerComponent('HelloWorld', () => Main);
控制台输出信息如下(由于样例中没有更新状态,也没有销毁组件。所以也就没有后面两个阶段):

四、总结
到这里,RN 组件完整的生命介绍完毕,回过头来看一下前面的图,就比较清晰了,把生命周期的回调函数总结成如下表格:
