一、对于useLayoutEffect的形容

Reactjs文档里这样形容useLayoutEffect

  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惟一的区别。

二、何时应用useLayoutEffect

假如有个展现随机数字的case,当count为0时随机生成个数字:

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>    );} 


能够看到展现0的过程。

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>    );}  

  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组件实现试试:

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成果一样:也是看不到闪动,但也比拟卡顿。

2.4 综上:

  1. useLayoutEffectcomponentDidMountcomponentDidUpdate触发机会统一(都在在DOM批改后且浏览器渲染之前);
  2. useLayoutEffect要比useEffect更早的触发执行;
  3. useLayoutEffect会阻塞浏览器渲染,切记执行同步的耗时操作。

三、小结:

除非要批改DOM并且不让用户看到批改DOM的过程,才思考应用useLayoutEffect,否则该当应用useEffect

留神:如果只是为了获取DOM属性(或其它get操作),则没必要应用useLayoutEffect,该当应用useEffect

四、参考:

整顿自gitHub笔记useEffectuseLayoutEffect到底有什么区别?