React生命周期笔记记录

React生命周期笔记记录

这里是参考网上资料加以整理的关于React生命周期的笔记(文中案例是自己真实手敲验证的哦~),以防今后自己可以更方便快捷的查询信息内容,参考的文章链接地址如下,感谢大家给予我这种技术小白提供知识的参考:
https://www.jianshu.com/p/514fe21b9914

一、组件初始化阶段

  • constructor()
import React, { Component } from 'react';

class Home extends Component {
  constructor(props) {
    super(props);
  }
}

1- super(props)用来调用基类的构造方法( constructor() ), 也将父组件的props注入给子组件,供子组件读取(组件中props只读不可变,state可变)。
2- 而constructor()用来做一些组件的初始化工作,如定义this.state的初始内容。

二、挂载阶段

  • componentWillMount

在组件挂载到DOM前调用,且只会被调用一次,在这边调用this.setState不会引起组件重新渲染,也可以把写在这边的内容提前到constructor()中,所以项目中很少用。

  • render

根据组件的props和state(无论两者的重传递和重赋值,值是否有变化,都可以引起组件重新render),return 一个React元素(描述组件,即UI),不负责组件实际渲染工作,之后由React自身根据此元素去渲染出页面DOM。render是纯函数(Pure function:函数的返回结果只依赖于它的参数;函数执行过程里面没有副作用),不能在里面执行this.setState,会有改变组件状态的副作用。

  • componentDidMount

组件挂载到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

结果如下图所示,但是,我们会发现,执行代码过程中会有一个警告提示:
React生命周期笔记记录_第1张图片
这是因为在react16中componentWillMount被弃用了,但是未被删除,需要使用UNSAFE_开头,即UNSAFE_componentWillMount,替换后警告提示消失:
React生命周期笔记记录_第2张图片
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

父组件更新前:
React生命周期笔记记录_第3张图片
点击更改标题按钮,父组件改变了state,重新渲染,子组件也跟着重新渲染:
React生命周期笔记记录_第4张图片
所以我们可以使用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

父组件更新前:
React生命周期笔记记录_第5张图片
点击更改标题按钮,父组件改变了state,重新渲染,子组件也跟着重新渲染:
React生命周期笔记记录_第6张图片

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

点击更改标题按钮,更新数据,生命周期执行顺序如下:
React生命周期笔记记录_第7张图片
四、卸载阶段

  • componentWillUnmount

此方法在组件被卸载前调用,可以在这里执行一些清理工作,比如清除组件中使用的定时器,清除componentDidMount中手动创建的DOM元素等,以避免引起内存泄漏。

React v16.4的生命周期

1-- 原来(React v16.0前)的生命周期在React v16推出的Fiber之后就不合适了,因为如果要开启async rendering,在render函数之前的所有函数,都有可能被执行多次
2-- 除了shouldComponentUpdate,其他在render函数之前的所有函数(componentWillMount,componentWillReceiveProps,componentWillUpdate)都被getDerivedStateFromProps替代

  • getDerivedStateFromProps
    要在getDerivedStateFromProps方法前加上static保留字,声明为静态方法,不然会报错:
    React生命周期笔记记录_第8张图片

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

执行顺序:
React生命周期笔记记录_第9张图片

  • getSnapshotBeforeUpdate

getSnapshotBeforeUpdate() 被调用于render之后,可以读取但无法使用DOM的时候。它使你的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。

(例子还没想到如何实现,哭泣~ 等我继续加油的。。。)

你可能感兴趣的:(React)