• react hooks 生命周期渲染时机简述


    使用hooks 已经有一段时间了,虽然团队都已经可以熟练应用到项目,但是没有深入理解hooks 的意思。state , useEffect 滥用,造成了多余的多次渲染。

    实战例子

    通过一个实现来了解下调用一个组件的一生,先看一下整个demo的样子。

    在这里插入图片描述

    整个结构是父组件调用红框子组件,子组件有一个title 是父组件传过来的属性,另一个subtitle 是一个state 按钮是刷新这个state 。

    父组件代码

     <div className={styles.container}>
            <Button
              type="primary"
              onClick={() => {
                setTitle((c) => {
                  return c + 'change';
                });
              }}
            >
              刷新子组件title
            </Button>
            <Button
            style={{"marginLeft":'30px'}}
              type="primary"
              onClick={() => {
                setVisible(false);
              }}
            >
              卸载子组件
            </Button>
    
            {visible && <ReturnView title={title}></ReturnView>}
          </div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    子组件代码
    
    import { Button } from 'antd';
    import React, { useEffect, useState } from 'react';
    const IndexPage: React.FC<{ title: string }> = ({ title }) => {
      const [subTitle, setSubTitle] = useState('subTitle');
    
      useEffect(() => {
        console.log('初始化加载');
    
        return () => {
          console.log('退出卸载');
        };
      }, []);
    
      useEffect(() => {
        console.log(`${subTitle}渲染完成之后`);
    
        return () => {
          console.log(`清除上次${subTitle}渲染`);
        };
      }, [subTitle]);
    
      useEffect(() => {
        console.log(`${title}渲染完成之后`);
    
        return () => {
          console.log(`清除上次${title}渲染`);
        };
      }, [title]);
    
      console.log('页面刷新');
    
      return (
        <div style={{ border: '5px solid red', marginTop: '16px' }}>
          <div>我是子组件</div>
          <div>{title}</div>
          <div>{subTitle}</div>
          <Button type="primary" onClick={() => setSubTitle('subTitle Change')}>
            {' '}
            刷新subtitle
          </Button>
        </div>
      );
    };
    export default IndexPage;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    组件的调用顺序

    在子组件加了一些打印来观察调用顺序,我们知道useEffect 是副作用,也就是函数组件调用完成的时候去回调安排副作用。

    当依赖项为空的时候,是第一次加载完成的时候调用,如果有依赖项,则依赖出发页面改变的时候去调用。

    关于retrun 通常useEffect 可以写return 闭包,那么这个return 的调用时机是什么呢?

    带着这些问题,我们用初次加载(useEffect 依赖为空数组)、监听属性(props)、监听state 分别进行测试。

    初次加载情景

    第一次加载也就是监听这部分逻辑,这个用hooks 的都知道就不多说。

     useEffect(() => {
        console.log('初始化加载');
    
        return () => {
          console.log('退出卸载');
        };
      }, []);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    项目运行打印结果:

    在这里插入图片描述

    一切在估计中,继续。

    卸载应用,验证retrun 是不是卸载时候调用,我们利用父视图显示卸载子组件。

    点击卸载子组件,触发打印,一切正常。

    在这里插入图片描述

    监听属性的变化

    我们用useEffect 监听props 属性的变化时机,return 是什么时候调用。

    useEffect(() => {
        console.log(`${title}渲染完成之后`);
    
        return () => {
          console.log(`清除上次${title}渲染`);
        };
      }, [title]);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    项目运行打印结果:
    在这里插入图片描述
    页面渲染完之后,同样执行了监听的props 。 那么props 的return 是什么时候调用呢?

    刷新title 属性试试,重外面更新title 属性,结果如下:

    在这里插入图片描述
    会先执行return 把上次的props 属性卸载掉,里面的props 值还是上次的。然后再执行进入。

    监听state的变化

      useEffect(() => {
        console.log(`${subTitle}渲染完成之后`);
    
        return () => {
          console.log(`清除上次${subTitle}渲染`);
        };
      }, [subTitle]);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    一如既往,useEffect 初始化的时候会这么调用。
    在这里插入图片描述

    那么return 是怎么运行的呢?我们改变state 试一试,同样会先执行return 然后再进入。

    在这里插入图片描述

    那么初始化、state 和 props 一起进入顺序如何

    跑第一遍:

    在这里插入图片描述
    先执行初始化,然后state 最后props 。 真的是这样吗?换个顺序试试

    换个顺序再来一遍:

    在这里插入图片描述

    wtf 顺序改变了。

    结论:

    进入的加载顺序和执行顺序有关,卸载之后同样。

  • 相关阅读:
    物理内存虚拟内存以及段页表
    sysbench--生产--02--mycat和mysql的性能
    (经典dp) 骨牌问题 2*n 3*n n*m
    Linux必会100个命令(五十六)tcpdump命令
    GaussDB(for MySQL) :Partial Result Cache,通过缓存中间结果对算子进行加速
    怎样基于VitePress(Vite官网主题)写自己文档
    【yolov5】原理详解
    代码随想录动day单调栈
    Kubernetes云原生实战02 对节点磁盘进行分区挂载
    uboot移植之环境变量bootcmd
  • 原文地址:https://blog.csdn.net/ZY_FlyWay/article/details/127426166