这里是参考网上资料加以整理的关于React生命周期的笔记(文中案例是自己真实手敲验证的哦~),以防今后自己可以更方便快捷的查询信息内容,参考的文章链接地址如下,感谢大家给予我这种技术小白提供知识的参考:
https://www.jianshu.com/p/514fe21b9914
一、组件初始化阶段
import React, { Component } from 'react';
class Home extends Component {
constructor(props) {
super(props);
}
}
1- super(props)
用来调用基类的构造方法( constructor() ), 也将父组件的props注入给子组件,供子组件读取(组件中props只读不可变,state可变)。
2- 而constructor()
用来做一些组件的初始化工作,如定义this.state的初始内容。
二、挂载阶段
在组件挂载到DOM前调用,且只会被调用一次,在这边调用this.setState不会引起组件重新渲染,也可以把写在这边的内容提前到constructor()中,所以项目中很少用。
根据组件的props和state(无论两者的重传递和重赋值,值是否有变化,都可以引起组件重新render),return 一个React元素(描述组件,即UI),不负责组件实际渲染工作,之后由React自身根据此元素去渲染出页面DOM。render是纯函数(Pure function:函数的返回结果只依赖于它的参数;函数执行过程里面没有副作用),不能在里面执行this.setState,会有改变组件状态的副作用。
组件挂载到DOM后调用,且只会被调用一次
执行顺序示例:
import React from "react";
class LifeCycle extends React.Component{
constructor(props) {
super(props);
console.log("1--第一个渲染")
}
componentWillMount(){ // UNSAFE_componentWillMount(使用此代码不会有警告提示)
console.log("2--第二个渲染")
}
componentDidMount(){
console.log("4--第四个渲染")
}
render(){
console.log("3--第三个渲染")
return(
<div className="lifeCycle">
<h4>react 生命周期</h4>
</div>
)
}
}
export default LifeCycle
结果如下图所示,但是,我们会发现,执行代码过程中会有一个警告提示:
这是因为在react16中componentWillMount被弃用了,但是未被删除,需要使用UNSAFE_开头,即UNSAFE_componentWillMount,替换后警告提示消失:
tip:同样原因的生命周期方法还有下面的UNSAFE_componentWillReceiveProps
三、更新阶段
setState引起的state更新或父组件重新render引起的props更新,更新后的state和props相对之前无论是否有变化,都将引起子组件的重新render。
造成组件更新有两类(三种)情况
1. 父组件重新render
A– 直接使用,每当父组件重新render导致的重传props,子组件将直接跟着重新渲染,无论props是否有变化。可通过shouldComponentUpdate方法优化。
父组件:LifeCycle
import React from "react";
import LifeChildren from './LifeChildren.jsx' //引入子组件
class LifeCycle extends React.Component{
constructor(props) {
super(props);
this.state={
title:'react 生命周期'
}
}
// 点击更改标题
ChangeTitle=()=>{
this.setState({
title:'react 生命周期 更改后'
})
}
render(){
return(
<div className="lifeCycle">
<h4>{this.state.title}</h4>
<button onClick={this.ChangeTitle.bind(this)}>更改标题</button>
<LifeChildren/> //子组件
</div>
)
}
}
export default LifeCycle
子组件:LifeChildren
import React from "react";
class LifeChildren extends React.Component{
constructor(props) {
super(props);
}
shouldComponentUpdate(nextProps){
// 应该使用这个方法,否则无论props是否有变化都将会导致子组件跟着重新渲染
if(nextProps.someThings === this.props.someThings){
console.log("我是子组件,我更新了,哈哈")
return false //阻止更新
}
}
render(){
return(
<div className="lifeChildren">
<h4>react 生命周期 子组件</h4>
</div>
)
}
}
export default LifeChildren
父组件更新前:
点击更改标题
按钮,父组件改变了state,重新渲染,子组件也跟着重新渲染:
所以我们可以使用shouldComponentUpdate(nextProps)
方法优化(return false),可阻止子组件随之更新。
B– 在componentWillReceiveProps
方法中,将props转换成自己的state,在该函数componentWillReceiveProps
中调用 this.setState()
将不会引起第二次渲染:这是因为componentWillReceiveProps
中判断props是否变化了,若变化了,this.setState
将引起state变化,从而引起render,此时就没必要再做第二次因重传props引起的render了,不然重复做一样的渲染了。
父组件:LifeCycle
import React from "react";
import LifeChildren from './LifeChildren.jsx' //引入子组件
class LifeCycle extends React.Component{
constructor(props) {
super(props);
this.state={
title:'react 生命周期'
}
}
// 点击更改标题
ChangeTitle=()=>{
this.setState({
title:'react 生命周期 更改后'
})
}
render(){
return(
<div className="lifeCycle">
<h4>{this.state.title}</h4>
<button onClick={this.ChangeTitle.bind(this)}>更改标题</button>
<LifeChildren friendTitle={this.state.title}/> //父组件给子组件传值
</div>
)
}
}
export default LifeCycle
子组件:LifeChildren
import React from "react";
class LifeChildren extends React.Component {
constructor(props) {
super(props);
this.state = {
title: props.friendTitle
};
}
UNSAFE_componentWillReceiveProps(nextProps) {
// 父组件重传props时就会调用这个方法,将内容转为自己的state
if(this.props.friendTitle == nextProps.friendTitle){
// 如果父组件更改前的值和更改后的值一样,可这样判断,阻止子组件不必要的更新
return false;
}else{
console.log("我是子组件 我执行componentWillReceiveProps了 哈哈")
this.setState({
title: nextProps.friendTitle
});
}
}
render() {
return (
<div className="lifeChildren">
<h4>react 生命周期 子组件</h4>
这是父组件里传过来的参数,在子组件里为我所用了,哈哈,内容为:{this.state.title}
</div>
)
}
}
export default LifeChildren
父组件更新前:
点击更改标题
按钮,父组件改变了state,重新渲染,子组件也跟着重新渲染:
2. 组件本身调用setState
无论state有没有变化。可通过shouldComponentUpdate方法优化。
– UNSAFE_componentWillReceiveProps(nextProps)
此方法只调用于props引起的组件更新过程中,参数nextProps是父组件传给当前组件的新props。但父组件render方法的调用不能保证重传给当前组件的props是有变化的,所以在此方法中根据nextProps和this.props来查明重传的props是否改变,以及如果改变了要执行什么操作,比如根据新的props调用this.setState触发当前组件的重新render
– shouldComponentUpdate(nextProps, nextState)
此方法通过比较nextProps,nextState及当前组件的this.props,this.state,返回true时当前组件将继续执行更新过程,返回false则当前组件更新停止,以此可用来减少组件的不必要渲染,优化组件性能。
tip:这边也可以看出,就算componentWillReceiveProps()中执行了this.setState,更新了state,但在render前(如shouldComponentUpdate,componentWillUpdate),this.state依然指向更新前的state,不然nextState及当前组件的this.state的对比就一直是true了。
– componentWillUpdate(nextProps, nextState)
此方法在调用render方法前执行,在这边可执行一些组件更新发生前的工作,一般较少用。
– render
重新调用渲染组件。
– componentDidUpdate(prevProps, prevState)
此方法在组件更新后被调用,可以操作组件更新的DOM,prevProps和prevState这两个参数指的是组件更新前的props和state
import React from "react";
import LifeChildren from './LifeChildren.jsx'
class LifeCycle extends React.Component{
constructor(props) {
super(props);
this.state={
title:'react 生命周期'
}
}
// 点击更改标题
ChangeTitle=()=>{
this.setState({
title:'react 生命周期 更改后'
})
}
// 更新=====
UNSAFE_componentWillReceiveProps(nextProps) {
console.log("只调用于props引起的组件更新过程中");
}
shouldComponentUpdate(nextProps, nextState){
console.log("1--更新第一步");
return true; //这里省略了判断,直接返回true
}
componentWillUpdate(nextProps, nextState){
console.log("2--更新第二步");
}
componentDidUpdate(prevProps, prevState){
console.log("4--更新第四步");
}
render(){
console.log("3--更新第三步");
return(
<div className="lifeCycle">
<h4>{this.state.title}</h4>
<button onClick={this.ChangeTitle.bind(this)}>更改标题</button>
</div>
)
}
}
export default LifeCycle
点击更改标题
按钮,更新数据,生命周期执行顺序如下:
四、卸载阶段
此方法在组件被卸载前调用,可以在这里执行一些清理工作,比如清除组件中使用的定时器,清除componentDidMount中手动创建的DOM元素等,以避免引起内存泄漏。
React v16.4的生命周期
1-- 原来(React v16.0前)的生命周期在React v16推出的Fiber之后就不合适了,因为如果要开启async rendering,在render函数之前的所有函数,都有可能被执行多次
2-- 除了shouldComponentUpdate,其他在render函数之前的所有函数(componentWillMount,componentWillReceiveProps,componentWillUpdate)都被getDerivedStateFromProps替代
static getDerivedStateFromProps(props, state)
在组件创建时和更新时在render方法之前调用,它应该返回一个对象来更新状态,或者返回null来不更新任何内容。
LifeCycle2.jsx
import React from "react";
import LifeChildren from './LifeChildren2.jsx'
class LifeCycle extends React.Component{
constructor(props) {
super(props);
this.state={
title:'react 生命周期'
}
console.log("1--第一个渲染")
}
// 挂载=====替代componentWillMount
static getDerivedStateFromProps(props,state){ //render之前
// console.log(props); // 挂载时:{ }
// console.log(state); // 挂载时:{title: "react 生命周期"}
console.log("2-挂载--新版本生命周期方法--render之前");
return true;
}
componentDidMount(){
console.log("4--第四个渲染")
}
// 点击更改标题
ChangeTitle=()=>{
this.setState({
title:'react 生命周期 更改后'
})
}
render(){
console.log("3-render");
return(
<div className="lifeCycle">
<h4>{this.state.title}</h4><button onClick={this.ChangeTitle.bind(this)}>更改标题</button>
{/* */ }
</div>
)
}
}
export default LifeCycle
getSnapshotBeforeUpdate() 被调用于render之后,可以读取但无法使用DOM的时候。它使你的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。
(例子还没想到如何实现,哭泣~ 等我继续加油的。。。)