第八节:React组件的生命周期

其实React组件并不是真正的DOM, 而是会生成JS对象的虚拟DOM, 虚拟DOM会经历创建,更新,删除的过程

这一个完整的过程就构成了组件的生命周期,React提供了钩子函数让我们可以在组件生命周期的不同阶段添加操作


1. 生命周期函数的理解

1.1 组件生命周期函数说明
  1. 组件生命周期函数主要分三类,组件的初始挂载,组件的更新渲染以及组件的卸载
  2. 有一些生命周期函数还在三个阶段都会执行的


1.2 组件的生命周期图
第八节:React组件的生命周期_第1张图片
生命周期流程图.png


2. 生命周期函数

2.1 组件初始挂载
2.1.1 组件初始挂载生命周期函数认识

当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:

  1. constructor: 完成React数据的初始化
  2. conponentWillMount/UNSAFE_componentWillMonut: 页面渲染前调用(未来将废弃)
  3. render : class组件中唯一必须实现的方法,返回React元素渲染页面
  4. componentDidMount 页面初始化渲染完毕以后执行


2.1.2 constructor函数

说明:

  1. 如果不需要初始化state,或者不进行方法的绑定,则不需要实现constructor构造函数
  2. 在组件挂载前调用构造函数,如果继承React.Component,则必须调用super(props)
  3. constructor通常用于处理了state初始化和为事件处理函数绑定this实例
  4. 尽量避免将props外部数据赋值给组件内部state状态

注意: constructor 构造函数只在初始化化的时候执行一次


示例代码如下:

class MyCom extends React.Component{
    
    // 1. constructor 构造函数
    constructor(props){
        super(props)
        console.log("组件初始化数据");
        // 初始化组件状态
        this.state = {
            count: 0
        }
        // 处理事件函数绑定组件实例
        this.handleClick = this.handleClick.bind(this)    
    }

    
    handleClick(){
        this.setState(() => ({
            count: ++ this.state.count
        }))


    }
    
    render(){
        return (
            

点击次数{ this.state.count }

) } } // 将组件渲染到页面上 ReactDOM.render( ,document.getElementById("root"))


之前有讲过组件state也可以不定义在constructor构造函数中,事件函数也可以通过箭头函数处理this问题

因此如果不想使用constructor 也可以将两者移出

示例代码如下

class MyCom extends React.Component{
  
    // 初始化组件状态
    state = {
        count: 0
    }

    // 箭头函数处理this问题
    handleClick= ()=>{
        this.setState(() => ({
            count: ++ this.state.count
        }))
    }
   //... 
}

结果一样正常显示


2.1.3 componentWillMount函数

说明:

  1. componentWillMount生命周期函数在组件渲染前执行,
  2. 使用时函数能正常运行, 但是控制台会打印警告,推荐使用UNSAFE_componentWillMount
  3. 但是react官网表示UNSAFE_componentWillMount即将过时,不建议使用
  4. 这个生命周期函数也只会执行一次

这个生命周期函数一般使用较少


示例代码:

class MyCom extends React.Component{
    // 1. 初始化构造函数
    constructor(props){
        super(props)
        console.log("组件初始化数据");
        // 初始化组件状态
        this.state = {
            count: 0
        }
        // 处理事件函数绑定组件实例
        this.handleClick = this.handleClick.bind(this)    
    }

    // 2.组件渲染前执行
    UNSAFE_componentWillMount(){
        console.log("组件内容渲染前执行 conponentWillMount");

    }

    handleClick(){
        this.setState(() => ({
            count: ++this.state.count
        }))


    }
    render(){
        return (
            

点击次数{ this.state.count }

) } } // 将组件渲染到页面上 ReactDOM.render( ,document.getElementById("root"))


2.1.4 render渲染函数

说明:

  1. class组件中唯一必须实现的方法,其他生命周期函数没有需求可以不写,这个必须实现
  2. render函数返回一个通过JSX语法创建的React元素
  3. render函数应为纯函数,意味着在不修改组件状态和父组件传递的props时,每次返回相同的结果
  4. render函数初始只会渲染一次,但是每次状态的改变都会重新执行


示例代码:

class MyCom extends React.Component{
    // 1. 初始化构造函数
    constructor(props){
        super(props)
        console.log("组件初始化数据");
        // 初始化组件状态
        this.state = {
            count: 0
        }
        // 处理事件函数绑定组件实例
        this.handleClick = this.handleClick.bind(this)    
    }

    // 2.组件渲染前执行
    UNSAFE_componentWillMount(){
        console.log("组件内容渲染前执行 conponentWillMount");

    }

    // 3. render渲染函数
    render(){
        console.log("render 渲染函数")
        return (
            

点击次数{ this.state.count }

) } // 自定义事件函数 handleClick(){ this.setState(() => ({ count: ++this.state.count })) } } // 将组件渲染到页面上 ReactDOM.render( ,document.getElementById("root"))


2.1.5 componentDidMount函数

说明:

  1. 组件渲染完毕以后执行, 在render渲染函数之后
  2. componentDidMount生命周期函数只会执行一次
  3. 可以在这个函数中发送ajax请求


示例代码:

class MyCom extends React.Component{
    // 1. 初始化构造函数
    constructor(props){
        super(props)
        console.log("组件初始化数据");
        // 初始化组件状态
        this.state = {
            count: 0
        }
        // 处理事件函数绑定组件实例
        this.handleClick = this.handleClick.bind(this)    
    }

    // 2.组件渲染前执行
    UNSAFE_componentWillMount(){
        console.log("组件内容渲染前执行 conponentWillMount");

    }

    // 3. render渲染函数
    render(){
        console.log("render 渲染函数")
        return (
            

点击次数{ this.state.count }

) } // 4.组件渲染完毕后执行 componentDidMount(){ console.log("组件内容渲染完毕,componentDidMount"); } // 自定义事件函数 handleClick(){ this.setState(() => ({ count: ++this.state.count })) } } // 将组件渲染到页面上 ReactDOM.render( ,document.getElementById("root"))


2.2 组件渲染更新

组件的更新会出现两种状况, 父组件传递的props更新以及当前组件更新自己的state

2.2.1 组件渲染更新生命周期函数认识
  1. componentWillReceiveProps 组件接受的Props将要更新
  2. shouldComponentUpdate 是否允许组件渲染更新,函数返回true表示通过, false表示不通过,渲染不更新
  3. componentWillUpdate/UNSAFE_componentWillUpdate 组件内容更新渲染前执行
  4. render 组件内容更新渲染
  5. componentDidUpdate 组件内容更新渲染之后执行


2.2.2 componentWillReceiveProps函数

说明:

  1. 在父组件传递的props更新时执行的生命周期函数
  2. 函数接受一个参数nextProps,为更新后的props数据
  3. 使用时控制台会打印警告, 建议使用UNSAFE_componentWillReceiveProps
  4. 但是官网表示UNSAFE_componentWillReceiveProps也将会被废弃



示例代码如下:

// 子组件
class MyCom extends React.Component{
  
  // 初始化组件状态
  state = {
    count: 0
  }

  // 1. 组件将要接受props更新
  componentWillReceiveProps(){
    console.log("组件将要接受props更新: componentWillReceiveProps");
  }


  render(){
    console.log("render 渲染函数")
    return (
      

父组件传递props数据{ this.props.num }

子组件state数据{ this.state.count }

) } // 自定义事件函数 handleClick=()=>{ this.setState(() => ({ count: ++this.state.count })) } } // 父组件 class MyParent extends React.Component{ state = { num:0 } changeNum = () => { this.setState(() => ({ num: ++ this.state.num }) ) } render(){ return (
) } } // 将组件渲染到页面上 ReactDOM.render( ,document.getElementById("root"))


2.2.3 shouldComponentUpdate函数

说明:

  1. shouldComponentUpdate函数使用来判读是否更新渲染组件
  2. 函数返回值是一个布尔值,为true,表示继续走其他的生命周期函数,更新渲染组件
  3. 如果返回一个false表示,不在继续向下执行其他的生命周期函数,到此终止,不更新组件渲染
  4. 函数接受两个参数, 第一个参数为props将要更新的数据, 第二个参数为state将要更新的数据


示例代码如下:

// 子组件
class MyCom extends React.Component{
  
  // 初始化组件状态
  state = {
    count: 0
  }

  // 1. 组件将要接受props更新
  componentWillReceiveProps(nextProps){
    console.log("组件将要接受props更新: componentWillReceiveProps");
   
    
  }

  // 2. 是否允许组件渲染更新
  shouldComponentUpdate(nextProps, nextState){
    console.log("是否允许组件渲染更新: shouldComponentupdate");
    return true
  }

 
  render(){
    console.log("render 渲染函数")
    return (
      

父组件传递props数据{ this.props.num }

子组件state数据{ this.state.count }

) } // 自定义事件函数 handleClick=()=>{ this.setState(() => ({ count: ++this.state.count })) } } // 父组件 //...


2.2.4 componentWillUpdate 函数

说明:

  1. componentWillUpdate组件更新渲染前执行
  2. 函数接受两个参数,第一个是props将要更新的数据,第二个是state将要更新的数据
  3. 使用是浏览器会警告, 建议使用UNSAFE_componentWillUpdate
  4. 但是官网表示UNSAFE_componentWillUpdate也将被废弃


示例代码:

class MyCom extends React.Component{
  
  // 初始化组件状态
  state = {
    count: 0
  }

  // 1. 组件将要接受props更新
 componentWillReceiveProps(nextProps){
    console.log("组件将要接受props更新: componentWillReceiveProps");
   
    
  }

  // 2. 是否允许组件渲染更新
  shouldComponentUpdate(nextProps, nextState){
    console.log("是否允许组件渲染更新: shouldComponentupdate");
    return true
  }

  // 3.组件渲染更新前
  componentWillUpdate(nextProps, nextState){
    console.log("组件内容更新前: componentWillUpdate");
   
  }

  render(){
    console.log("render 渲染函数")
    return (
      

父组件传递props数据{ this.props.num }

子组件state数据{ this.state.count }

) } // 自定义事件函数 handleClick=()=>{ this.setState(() => ({ count: ++this.state.count })) } } // 父组件 //...


2.2.5 render函数

更初始化一样,没事数据更新都会触发render函数重新执行, 更新页面渲染


2.2.6 componentDidUpdate函数

说明:

  1. 组件render执行后,页面渲染完毕了以后执行的函数
  2. 接受两个参数,分别为更新前的props和state


示例代码如下:

// 子组件
class MyCom extends React.Component{
  
  // 初始化组件状态
  state = {
    count: 0
  }

  // 1. 组件将要接受props更新
 componentWillReceiveProps(nextProps){
    console.log("组件将要接受props更新: componentWillReceiveProps");
   
    
  }

  // 2. 是否允许组件渲染更新
  shouldComponentUpdate(nextProps, nextState){
    console.log("是否允许组件渲染更新: shouldComponentupdate");
    return true
  }

  // 3.组件渲染更新前
  componentWillUpdate(){
    console.log("组件内容更新前: componentWillUpdate");
   
  }

  // 4. render渲染函数
  render(){
    console.log("render 渲染函数")
    return (
      

父组件传递props数据{ this.props.num }

子组件state数据{ this.state.count }

) } // 5. 组件内容更新渲染后 componentDidUpdate( prevProps, prevState){ console.log("组件内容更新后执行"); } // 自定义事件函数 handleClick=()=>{ this.setState(() => ({ count: ++this.state.count })) } } // 父组件 //...


2.3 组件销毁

说明:

  1. 组件销毁阶段只有一个生命周期函数componentWillUnmount
  2. componentWillUnmont组件销毁前执行的生命周期函数,
  3. 没有组件销毁后执行的生命周期函数, 没什么意义,组件被销毁了,获取不到对应的内容了
  4. 通过会在组件销毁前清理一些不会被组件自动清理的内容, 如: 定时器,或一些特殊的事件绑定


示例代码:

// 子组件
class MyCom extends React.Component{

    // 初始化组件状态
    state = {
        count: 0
    }

    render(){
        console.log("render 渲染函数")
        return (
            

父组件传递props数据{ this.props.num }

子组件state数据{ this.state.count }

) } componentWillUnmount(){ console.log("组件被销毁前执行:componentWillUnmount") } // 自定义事件函数 handleClick=()=>{ this.setState(() => ({ count: ++this.state.count })) } } // 父组件 class MyParent extends React.Component{ state = { isShow: true } changeNum = () => { this.setState(() => ({ isShow: !this.state.isShow }) ) } render(){ return (
{ this.state.isShow ? : "组件不显示"}
) } } // 将组件渲染到页面上 ReactDOM.render( ,document.getElementById("root"))


2.4 getSnapshotBeforeUpdate函数

说明:

  1. getSnapshotBeforeUpdate必须跟componentDidUpdate一起使用,否则就报错
  2. 但是不能与componentWillReceivePropscomponentWillUpdate一起使用
  3. state和props更新都会触发这个函数的执行, 在render函数之后执行
  4. 接受两个参数,更新前的props和当前的state
  5. 函数必须return 返回结果
  6. getSnapshotBeforeUpdate返回的结果将作为参数传递给componentDidUpdate


示例代码如下:

class MyCom extends React.Component{
  
  // 初始化组件状态
  state = {
    count: 0
  }

  render(){
    console.log("render 渲染函数")
    return (
      

父组件传递props数据{ this.props.num }

子组件state数据{ this.state.count }

) } getSnapshotBeforeUpdate(){ console.log("getSnapshotBeforeUpdate") return true } componentDidUpdate(){ console.log("组件内容更新后执行"); } // 自定义事件函数 handleClick=()=>{ this.setState(() => ({ count: ++this.state.count })) } } // 父组件 class MyParent extends React.Component{ state = { isShow: true, num : 0 } changeShow = () => { this.setState(() => ({ isShow: !this.state.isShow }) ) } changeNum = () => { this.setState(() => ({ num: ++this.state.num }) ) } render(){ return (
{ this.state.isShow ? : "组件不显示"}
) } } // 将组件渲染到页面上 ReactDOM.render( ,document.getElementById("root"))


2.5 生命周期函数参数
第八节:React组件的生命周期_第2张图片
生命周期函数参数.png


2.6 特殊情况的生命周期函数

在React 17 版本之后将会改变几个生命周期函数

第八节:React组件的生命周期_第3张图片
更改的生命周期函数.png


3. React 新增生命周期函数

3.1 新版生命周期图

添加静态方法后的生命周期函数图

新的生命周期函数图.png
第八节:React组件的生命周期_第4张图片
不常用生命周期图.png


3.2 新增的静态方法

说明:

  1. react新增了静态方法getDerviedStateFromProps方法在生命周期中
  2. 这个方法用来替换componentWillReceiveProps,
  3. 通常会在ComponentWillReceiveProps中利用Props更新state
  4. getDerivedStateFromProps方法接受两个参数, 将要更新的props和state属性
  5. 需要返回一个布尔值,不然会报错
  6. 还可以取代componentWillMount的功能, 因为这个静态方法在组件初始化也会执行


示例代码:

class MyCom extends React.Component{
  
  // 初始化组件状态
  state = {
    count: 0
  }

  // 生命周期上新增的静态方法
  static getDerivedStateFromProps(nextProps,nextState){
    console.log("getDerivedStateFromProps");
      
      // 利用props的值更新当前组件的状态
    nextState.count = nextProps.num
    return true
  }


  render(){
    console.log("render 渲染函数")
    return (
      

父组件传递props数据{ this.props.num }

子组件state数据{ this.state.count }

) } // 自定义事件函数 handleClick=()=>{ this.setState(() => ({ count: ++this.state.count })) } } // 父组件 class MyParent extends React.Component{ state = { isShow: true, num : 0 } changeShow = () => { this.setState(() => ({ isShow: !this.state.isShow }) ) } changeNum = () => { this.setState(() => ({ num: ++this.state.num }) ) } render(){ return (
{ this.state.isShow ? : "组件不显示"}
) } } // 将组件渲染到页面上 ReactDOM.render( ,document.getElementById("root"))


4. 组件更新的方法

组件更新自己的状态,除了使用setState更新外,还可以通过forceUpdate更新

4.1 forceUpdate

说明:

  1. 在组件中也可以组件实例调用forceUpdate方法直接更新数据
  2. forceUpdate方法会强制更新状态,
  3. forceUpdate方法会执行静态方法getDerivedStateFromProps函数
  4. 但是forceUpdate方法不会触发shouldComponetUpdate判断是否更新的生命周期函数


示例代码:

class MyCom extends React.Component{

    // 初始化组件状态
    state = {
        count: 0
    }

    // 2. 是否允许组件渲染更新
    shouldComponentUpdate(nextProps, nextState){
        console.log("是否允许组件渲染更新: shouldComponentupdate");
        // nextState.count = nextProps.num
        return true
    }

    
    static getDerivedStateFromProps(nextProps,nextState){
        console.log("getDerivedStateFromProps");
        
        console.log(arguments);

        return true
    }


    // 自定义事件函数
    handleClick=()=>{
        this.state.count = ++ this.state.count

        this.forceUpdate();
    }

    // 4. render渲染函数
    render(){
        console.log("render 渲染函数")
        return (
            

父组件传递props数据{ this.props.num }

子组件state数据{ this.state.count }

) } } // 父组件 //...

示例说明:

  1. 示例中直接修改状态并不会触发重新渲染
  2. 但是通过组件实例调用forceUpdate强制更新,会重新触发页面渲染
  3. 会触发生命周期getDerivedStateFromProps函数执行,
  4. 但是不会是否判断是否更新的shouldComponentUpdate函数的执行


5. 生命周期总结

5.1 常用生命周期函数

说明:

  1. React生命周期函数很多, 但是并不是每一个都是那么的常用
  2. 因此可以将生命周期图简化一下

常用生命周期图

第八节:React组件的生命周期_第5张图片
常用生命周期图.png


5.2 生命周期总结
5.2.1 组件的三个生命周期分三个阶段
  1. Mount : 初始化插入真实DOM
  2. Update : 数据更改重新渲染
  3. Unmount: 被移出真实的DOM


5.2.2 生命周期不同阶段的钩子函数
  • 第一次初始化渲染显示: ReactDOM.render()

    • constructor(): 创建对象初始化state

    • componentWillMount() : 将要插入回调

    • render(): 用于插入虚拟DOM回调

    • componentDidMount() : 已经插入回调(启动定时器,发送ajax,只执行一次)

  • 每次更新 state: this.setState()

    • componentWillUpdate() : 将要更新回调

    • render() : 更新(重新渲染)

    • componentDidUpdate() : 已经更新回调

  • 移除组件 : ReactDOM.unmountComponentAtNode(containerDom)
    • componentWillUnmount() : 组件将要被移出回调(收尾工作,例如清除定时器)


5.2.3 重要的钩子函数
  • render(): 初始化渲染或更新渲染调用

  • componentDidMount() : 开启监听,发送ajax请求

  • componentWillUnmount(): 做一些收尾工作,如,清理定时器


5.3 示例代码:

// 1. 定义组件
class Files extends React.Component {

    constructor (){
        super()

        // 定义状态
        this.state = {
            opacity: 1
        }

    }
    removeComponent () {
        // 执行unmountComponentAtNode()移出DOM节点
        ReactDOM.unmountComponentAtNode(document.getElementById('root'))
    }


    // 组件添加完后执行的钩子函数
    componentDidMount () {
        console.log('componentDidMount()')

        // 开启定时器
        this.timer = setInterval(function(){
            console.log('定时器...')

            // 1. 获取状态中的值
            let {opacity} = this.state;

            // 2. 改变透明度
            opacity -= 0.1;

            // 3. 判断透明度,如果小于0,就变为1
            if(opacity <= 0){
                opacity = 1
            }

            // 4. 改变状态
            this.setState({
                opacity
            })

        }.bind(this),200)
    }


    // 组件被移出后执行的钩子函数
    componentWillUnmount(){
        console.log('componentWillUnmount()')

        // 组件被移除后清除定时器
        clearInterval(this.timer)
    }

   
    render(){
        console.log('render()')
        // 取出状态中的透明度
        let {opacity} = this.state;

        return (
            

{this.props.msg}

) } } // 设置props类型 Files.propTypes = { msg: PropTypes.string } // 2. 渲染组件标签 ReactDOM.render( , document.getElementById('root') )

你可能感兴趣的:(第八节:React组件的生命周期)