本文详细介绍了 React 生命周期的用法以及各个阶段的生命周期进行,而且用实例代码作了详细演示。代码位置html
上图是基于 React 16.4 以后的生命周期图解。如感受不对,请先查看 React 版本react
在 React 组件挂载以前被调用,实现 React.Component
的子类的构造函数时,要在第一行加上 super(props)。git
React 构造函数一般只用于两个目的:github
this.state
来初始化本地 state
若是没有初始化状态(state
),而且没有绑定方法,一般不须要为 React
组件实现一个构造函数。浏览器
不须要在构造函数中调用
setState()
,只需将初始状态设置给this.state
便可 。性能优化
getDerivedStateFromProps
在每次调用 render 方法以前调用。包括初始化和后续更新时。网络
包含两个参数:第一个参数为即将更新的
props
值,第二个参数为以前的state
值函数
返回值:返回为
null
时,不作任何反作用处理。假若想更新某些state
状态值,则返回一个对象,就会对state
进行修改性能
该生命周期是静态函数,属于类的方法,其做用域内是找不到
this
的测试
render()
方法是类组件中惟一必须的方法,其他生命周期不是必需要写。 组件渲染时会走到该生命周期,展现的组件都是由 render() 生命周期的返回值来决定。
注意: 若是 shouldComponentUpdate() 方法返回 false ,render() 不会被调用。
在 React 组件装载(mounting)(插入树)后被当即调用。
componentDidMount 生命周期是进行发送网络请求、启用事件监听的好时机
若是有必要,能够在今生命周期中马上调用 setState()
在组件准备更新以前调用,能够控制组件是否进行更新,返回 true 时组件更新,返回 false 组件不更新。
包含两个参数,第一个是即将更新的 props 值,第二个是即将跟新后的 state 值,能够根据更新先后的 props 或 state 进行判断,决定是否更新,进行性能优化
不要
shouldComponentUpdate
中调用 setState(),不然会致使无限循环调用更新、渲染,直至浏览器内存崩溃
getSnapshotBeforeUpdate()
在最近一次的渲染输出被提交以前调用。也就是说,在 render 以后,即将对组件进行挂载时调用。
它可使组件在 DOM 真正更新以前捕获一些信息(例如滚动位置),今生命周期返回的任何值都会做为参数传递给
componentDidUpdate()
。如不须要传递任何值,那么请返回 null
componentDidUpdate()
在更新发生以后当即被调用。这个生命周期在组件第一次渲染时不会触发。
能够在今生命周期中调用 setState(),可是必须包含在条件语句中,不然会形成无限循环,最终致使浏览器内存崩溃
componentWillUnmount()
在组件即将被卸载或销毁时进行调用。
今生命周期是取消网络请求、移除监听事件、清理 DOM 元素、清理定时器等操做的好时机
注意: componentWillMount()、componentWillUpdate()、componentWillReceiveProps() 即将被废弃,请不要再在组件中进行使用。所以本文不作讲解,避免混淆。
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentWillUnmount()
下面根据一个父子组件的props 改变、state 改变以及子组件的挂载/卸载等事件,对各生命周期执行顺序进行理解,有兴趣的同窗能够一块儿看一下,也能够下载代码本身进行测试。
import React, { Component } from 'react';
import Child from './Child.js';
const parentStyle = {
padding: 40,
margin: 20,
border: '1px solid pink'
}
const TAG = "Parent 组件:"
export default class Parent extends Component {
constructor(props) {
super(props);
console.log(TAG, 'constructor');
this.state = {
num: 0,
mountChild: true
}
}
static getDerivedStateFromProps(nextProps, prevState) {
console.log(TAG, 'getDerivedStateFromProps');
return null;
}
componentDidMount() {
console.log(TAG, 'componentDidMount');
}
shouldComponentUpdate(nextProps, nextState) {
console.log(TAG, 'shouldComponentUpdate');
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log(TAG, 'getSnapshotBeforeUpdate');
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log(TAG, 'componentDidUpdate');
}
componentWillUnmount() {
console.log(TAG, 'componentWillUnmount');
}
/** * 修改传给子组件属性 num 的方法 */
changeNum = () => {
let { num } = this.state;
this.setState({
num: ++ num
});
}
/** * 切换子组件挂载和卸载的方法 */
toggleMountChild = () => {
let { mountChild } = this.state;
this.setState({
mountChild: !mountChild
});
}
render() {
console.log(TAG, 'render');
const { num, mountChild } = this.state;
return (
<div style={ parentStyle }> <div> <p>父组件</p> <button onClick={ this.changeNum }>改变传给子组件的属性 num</button> <br /> <br /> <button onClick={ this.toggleMountChild }>卸载 / 挂载子组件</button> </div> { mountChild ? <Child num={ num } /> : null } </div> ) } } 复制代码
import React, { Component } from 'react'
const childStyle = {
padding: 20,
margin: 20,
border: '1px solid black'
}
const TAG = 'Child 组件:'
export default class Child extends Component {
constructor(props) {
super(props);
console.log(TAG, 'constructor');
this.state = {
counter: 0
};
}
static getDerivedStateFromProps(nextProps, prevState) {
console.log(TAG, 'getDerivedStateFromProps');
return null;
}
componentDidMount() {
console.log(TAG, 'componentDidMount');
}
shouldComponentUpdate(nextProps, nextState) {
console.log(TAG, 'shouldComponentUpdate');
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log(TAG, 'getSnapshotBeforeUpdate');
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log(TAG, 'componentDidUpdate');
}
componentWillUnmount() {
console.log(TAG, 'componentWillUnmount');
}
changeCounter = () => {
let { counter }= this.state;
this.setState({
counter: ++ counter
});
}
render() {
console.log(TAG, 'render');
const { num } = this.props;
const { counter } = this.state;
return (
<div style={ childStyle }> <p>子组件</p> <p>父组件传过来的属性 num : { num }</p> <p>自身状态 counter : { counter }</p> <button onClick={ this.changeCounter }>改变自身状态 counter</button> </div>
)
}
}
复制代码
父子组件第一次进行渲染加载时,界面展现为:
控制台中的 log 打印顺序为:
点击子组件中的 改变自身状态 按钮,则界面上 自身状态 counter: 的值会 + 1,控制台中的 log 打印顺序为:
点击父组件中的 改变传给子组件的属性 num 按钮,则界面上 父组件传过来的属性 num: 的值会 + 1,控制台中的 log 打印顺序为:
点击父组件中的 卸载 / 挂载子组件 按钮,则界面上子组件会消失,控制台中的 log 打印顺序为:
再次点击父组件中的 卸载 / 挂载子组件 按钮,则界面上子组件会从新渲染出来,控制台中的 log 打印顺序为:
当子组件自身状态改变时,不会对父组件产生反作用的状况下,父组件不会进行更新,即不会触发父组件的生命周期
当父组件中状态发生变化(包括子组件的挂载以及)时,会触发自身对应的生命周期以及子组件的更新
render 以及 render 以前的生命周期,则 父组件 先执行
render 以及 render 以后的声明周期,则子组件先执行,而且是与父组件交替执行
当子组件进行卸载时,只会执行自身的 componentWillUnmount 生命周期,不会再触发别的生命周期
可能总结的很差,不是很完整。只是根据通常状况进行的总结。有不妥之处,但愿各位朋友可以多多指正。
源码地址(欢迎 Star,谢谢!)
还没看够?移步至:React Component 官网