什么时候使用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

相关文章
相关标签/搜索