什麼時候使用useLayoutEffect?

1、關於useLayoutEffect的描述

Reactjs文檔裏這樣描述useLayoutEffecthtml

  1. The signature is identical to useEffect, but it fires synchronously after all DOM mutations
  2. only differs in when it is fired

useLayoutEffectuseEffect函數簽名一致,可是在DOM修改後同步觸發,這是和useEffect惟一的區別。react

2、什麼時候使用useLayoutEffect

假設有個展現隨機數字的case,當count爲0時隨機生成個數字:git

2.1 先使用useEffect實現:

import { useState, useEffect, useLayoutEffect } from 'react'

export default function App() {
    const [count, setCount] = useState(0);
    
    useEffect(() => {
        console.log(`useEffect - count=${count}`)
        // 耗時的操做
        const pre = Date.now();
        while(Date.now() - pre < 500) {}
        
        // count爲0時從新生成個隨機數
        if (count === 0) {    
            setCount(10 + Math.random() * 200);
        }
    }, [count]);
    
    // 點擊DIV重置count
    return (
        <div onClick={() => setCount(0)}>{count}</div>
    );
}

flicker
能夠看到展現0的過程。github

2.2 改用useLayoutEffect實現:

import { useState, useEffect, useLayoutEffect } from 'react'

export default function App() {
    const [count, setCount] = useState(0);
    
    useLayoutEffect(() => {
        console.log(`useLayoutEffect - count=${count}`)
        // 耗時的操做
        const pre = Date.now();
        while(Date.now() - pre < 500) {}

        if (count === 0) {    
            setCount(10 + Math.random() * 200);
        }
    }, [count]);
  
    return (
        <div onClick={() => setCount(0)}>{count}</div>
    );
}

no_flicker

  1. 沒有閃爍,當點擊 div,count 更新爲 0,此時頁面並不會渲染,而是等待useLayoutEffect內部狀態修改後,纔會去更新頁面,因此頁面不會閃爍。瀏覽器

    Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint
  2. 可是也能夠發現頁面更新的比較卡頓,由於useLayoutEffect會阻塞瀏覽器渲染,正好本例中useLayoutEffect的實參函數裏有個耗時操做,因此頁面更新比較卡頓。

2.3 useLayoutEffectcomponentDidMountcomponentDidUpdate觸發時機一致

上面的例子改用class組件實現試試:dom

import React from 'react'

export default class App extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
    }

    componentDidUpdate() {
        // 耗時的操做
        const pre = Date.now();       
        while(Date.now() - pre < 500) {}
    }

    increaseCount = () => {
        this.setState(({ count }) => {
            return { count: count + 1}
        })
    }

    render() {
        const { count } = this.state;
        return (
            <div onClick={this.increaseCount}>{count}</div>
        )
    }
}

useLayoutEffect效果同樣:也是看不到閃爍,但也比較卡頓。ide

2.4 綜上:

  1. useLayoutEffectcomponentDidMountcomponentDidUpdate觸發時機一致(都在在DOM修改後且瀏覽器渲染以前);
  2. useLayoutEffect要比useEffect更早的觸發執行;
  3. useLayoutEffect會阻塞瀏覽器渲染,切記執行同步的耗時操做。

3、小結:

除非要修改DOM而且不讓用戶看到修改DOM的過程,才考慮使用useLayoutEffect,不然應當使用useEffect函數

注意:若是隻是爲了獲取DOM屬性(或其它get操做),則不必使用useLayoutEffect,應當使用useEffectthis

4、參考:

整理自gitHub筆記useEffectuseLayoutEffect到底有什麼區別?spa

相關文章
相關標籤/搜索