• React函数式组件渲染、useEffect顺序总结


    参考资料:
    深入React的生命周期(上):出生阶段(Mount)
    深入React的生命周期(下):更新(Update)
    精读《useEffect 完全指南》
    React组件重新渲染理解 & 优化大全
    React渲染顺序及useEffect执行顺序探究(含并发模式)

    组件状态

    同样还是可以把组件的状态分为mount、update和unmount。

    • mount:组件首次出现在页面中。React会通过最后组件的函数返回值,确定它有哪些子组件,依次mount和render子组件。一个component只是定义了,但没有最后被返回,就不会被挂载和渲染。
    • update:组件的重新渲染,重新渲染的条件见这里
    • unmount:如果组件从页面消失,就会被unmount。常见于条件渲染、或者子组件未使用key标明时的位置更改。

    React16的组件渲染过程

    即使用ReactDOM.createRoot(DOM).render()渲染组件时。

    单一组件渲染过程

    在组件的不同阶段,调用顺序如下

    mount

    • 函数体:此时useState等hooks取初始值,如果用callback初始化,则会调用初始化函数
    • effect函数:会调用一遍所有useEffect注册的函数,调用顺序就是useEffect在函数体里出现的顺序

    update

    • 函数体:正常调用,取最新state和ref的值

    • clean函数:如果依赖项A=[…]发生改变,则会调用,但若有其它依赖项B也变了,却没列进依赖项里,这些未注册依赖项会使用最后一次A=[…]发生改变时的B的值。因为这是clean函数最新的定义。

      样例可见React函数式组件渲染顺序探究(Demo),组件依赖了name和state,但只注册了state这一个依赖项。

    • effect函数:如果依赖项A=[…]发生改变,则会调用,但若有其它依赖项B也变了,却没列进依赖项里,这些未注册依赖项会使用最后一次A=[…]发生改变时的B的值。因为这是effect函数最新的定义。

    unmount

    • clean函数:会调用一遍所有useEffect返回的clean函数,调用顺序也是注册顺序。同样,也取的是它最新的定义。

      假设有两个effect,都有未注册依赖项B。但它们一个依赖项为A=[…],另一个为[]

      如果最开始B=1,而A变的时候B=2,最后unmount的时候,前者的B=2,后者的B=1,因为后者的clean函数并未更新。

    树型组件调用顺序

    mount

    如果有一个这样的component:

    <A>
        <A1>
            <A1_1/>
            <A1_2/>
        A1>
        <A2>
            <A2_1/>
            <A2_2/>
        A2>
    A>
    
    • 函数体:调用顺序是先序遍历的DFS,即[A, A1, A1_1, A1_2, A2, A2_1, A2_2]
    • effect:类似于二叉树的后序遍历,先遍历孩子,再遍历根,即:[A1_1, A1_2, A1, A2_1, A2_2, A2, A]

    update

    如果上述的component变成了如下,A重新渲染。

    <A>
        <A2>
            <A2_1/>
            <A2_2/>
        A2>
        <A1>
            <A1_1/>
            <A1_2/>
        A1>
    A>
    
    • 如果A1和A2没有设置key,React会当作需要unmount旧的A1、A2,再mount新的A1、A2。
    • 否则,React只会重新渲染A1、A2。

    假设这里A1设置了key,而A2没有:

    • 函数体:按当前组件内容的先序DFS:[A1, A1_1, A1_2, A2, A2_1, A2_2]
    • clean:
      • 先执行unmount的组件的clean,执行顺序是先序DFS,即[A2, A2_1, A2_2]
      • 再执行update组件的clean,执行顺序是后序DFS,即[A1_1, A1_2, A1]
    • effect:按当前组件内容的后序DFS执行,即[A2_1, A2_2, A2, A1_1, A1_2, A1]

    React18的更新

    即使用StrictMode渲染组件时。

    root.render(
      <React.StrictMode>
        <App />
      React.StrictMode>
    );
    

    与16最大的区别是:

    (1)函数体都会被调用2遍

    (2)新mount的组件都会再次调用一遍clean和effect

    有点类似于, mount (React 18)约等于mount(React 16) + update(React 16)

    所以:

    • 第一次body即mount的body,第二次body是update的body

      但也不完全相同,比如,如果使用callback来初始化state的值时,mount的时候调用的两遍函数体,都是会调用这个callback的,而不是一次调用一次不调用。

    • 第一次effect是mount的effect

    • 接下来的clean和effect是update时的clean+effect

    mount

    如果有一个这样的component:

    <A>
        <A1>
            <A1_1/>
            <A1_2/>
        A1>
        <A2>
            <A2_1/>
            <A2_2/>
        A2>
    A>
    
    • 函数体:调用顺序是先序遍历的DFS,即[A, A1, A1_1, A1_2, A2, A2_1, A2_2]。由于会叫两遍,实际上是[A, A, A1, A1, A1_1, A1_1, A1_2, A1_2, A2, A2, A2_1, A2_1, A2_2, A2_2]
      • 有意思的是,不是先mount DFS一遍,update DFS一遍,是在DFS的过程中直接叫两遍函数体。
    • effect:类似于二叉树的后序遍历,先遍历孩子,再遍历根,即:[A1_1, A1_2, A1, A2_1, A2_2, A2, A]
    • clean:后序DFS[A1_1, A1_2, A1, A2_1, A2_2, A2, A]
    • effect:后序DFS[A1_1, A1_2, A1, A2_1, A2_2, A2, A]

    update

    如果上述的component变成了如下,A重新渲染。

    <A>
        <A2>
            <A2_1/>
            <A2_2/>
        A2>
        <A1>
            <A1_1/>
            <A1_2/>
        A1>
    A>
    
    • 如果A1和A2没有设置key,React会当作需要unmount旧的A1、A2,再mount新的A1、A2。
    • 否则,React只会重新渲染A1、A2。

    假设这里A1设置了key,而A2没有:

    • 函数体:按当前组件内容的先序DFS:[A1, A1_1, A1_2, A2, A2_1, A2_2]。同样会调用2次。
    • clean:
      • 先执行unmount的组件的clean,执行顺序是先序DFS,即[A2, A2_1, A2_2]
      • 再执行update组件的clean,执行顺序是后序DFS,即[A1_1, A1_2, A1]
    • effect:按当前组件内容的后序DFS执行,即[A2_1, A2_2, A2, A1_1, A1_2, A1]
    • clean:mount的组件会被update,所以会有第二轮clean,后序DFS,即[A2_1, A2_2, A2]
    • effect:第二轮effect,即[A2_1, A2_2, A2]
  • 相关阅读:
    起风了,NCC 云原生项目孵化计划
    Pytorch 下 TensorboardX 使用
    【Linux进程】进程状态---进程僵尸与孤儿
    ESP8266-Arduino编程实例-PCT2075温度数字转换器驱动
    实现二叉树先序,中序和后序遍历
    力扣279题:完全平方数
    信息学奥赛一本通 1435:【例题3】曲线 | 洛谷 洛谷 P1883 函数
    「技术」智能温室可升降吊挂式草莓立体无土栽培技术分析
    [makeself|shell] 使用makeself制作linux应用程序安装包
    【C语言】归并排序算法实现
  • 原文地址:https://www.cnblogs.com/milliele/p/17578048.html