React Hooks系列之useLayoutEffect

前言

react hooks 是 React 16.8 的新增特性。 它可以让我们在函数组件中使用 state 、生命周期以及其他 react特性,而不仅限于 class 组件。react hooks 的出现,标示着 react中不会在存在无状态组件了,只有类组件和函数组件。具体可查看官网。

优势:

  1. 函数组件不能使用state,遇到交互更改状态等复杂逻辑时不能更好地支持,hooks让函数组件更靠近class组件,拥抱函数式编程。
  2. 解决副作⽤问题,hooks出现可以处理数据获取、订阅、定时执行任务、手动修改 ReactDOM这些⾏为副作用,进行副作用逻辑。比如useEffect。
  3. 更好写出有状态的逻辑重用组件。
  4. 让复杂逻辑简单化,比如状态管理:useReducer、useContext。
  5. 函数式组件比class组件简洁,开发的体验更好,效率更⾼,性能更好。
  6. 更容易发现无用的状态和函数。

useLayoutEffect介绍

其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。

尽可能使用标准的 useEffect 以避免阻塞视觉更新。

useLayoutEffect 的使用方法和 useEffect 相同,唯一的区别就是执行时机不一样。

useLayoutEffect使用

对比 useLayoutEffect 与 useEffect 的执行时机

import React, {
      useState, useEffect, useLayoutEffect } from 'react';
import ReactDOM from 'react-dom';

function Com() {
     
  useEffect(() => {
     
    console.log('useEffect 执行...');
    return () => {
     
      console.log('useEffect 销毁...');
    }
  });

  useLayoutEffect(() => {
     
    console.log('useLayoutEffect 执行...');
    return () => {
     
      console.log('useLayoutEffect 销毁...');
    }
  });

  return (
    <div>
      {
     console.log('Com 渲染')}
      <h2>Com1</h2>
    </div>
  )
}

const App = props => {
     
  const [ count, setCount ] = useState(0)
  return (
    <div>
      <Com />
      {
     count}
      <button onClick={
     () => setCount(count + 1)}>count + 1</button>
    </div>
  )
}

ReactDOM.render(<App />, root);

上面的例子中在 Com 组件中同时使用了 useLayoutEffect 和 useEffect,在页面初次渲染时可以看到控制台打印顺序为 Com 渲染 → useLayoutEffect 执行… → useEffect 执行…。

当点击 App 组件按钮更新状态导致 Com 重新渲染,打印顺序为 Com 渲染 → useLayoutEffect 销毁… → useLayoutEffect 执行… → useEffect 销毁… → useEffect 执行…。

在刚接触 React Hooks 时,说到执行时机我们一般会和类组件的生命周期去类比,下面是一个 useLayoutEffect、useEffect 与类组件生命周期配合使用的例子。

对比 useLayoutEffect、useEffect 与类组件生命周期的执行时机

import React, {
      useEffect, useLayoutEffect, Component } from 'react';
import ReactDOM from 'react-dom';

// 使用 useLayoutEffect 和 useEffect 的函数组件
function Com() {
     
  useEffect(() => {
     
    console.log('useEffect 执行...');
    return () => {
     
      console.log('useEffect 销毁...');
    }
  });

  useLayoutEffect(() => {
     
    console.log('useLayoutEffect 执行...');
    return () => {
     
      console.log('useLayoutEffect 销毁...');
    }
  });

  return (
    <div>
      {
     console.log('Com 渲染')}
      <h2>Com1</h2>
    </div>
  )
}

// 使用生命周期的类组件
class App extends Component {
     
  state = {
      count: 0 }
  setCount = () => {
     
    this.setState({
      count: this.state.count + 1 });
  }
  componentDidMount() {
     
    console.log('App componentDidMount');
  }
  componentDidUpdate() {
     
    console.log('App componentDidUpdate');
  }
  render() {
     
    return (
      <div>
        {
     this.state.count}
        <Com />
        {
     console.log('App 渲染')}
        <button onClick={
     this.setCount}>count + 1</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, root);

上面例子中 useLayoutEffect 和 useEffect 依然在 Com 组件中使用,App 组件为类组件,Com 作为 App 的子组件,在首次渲染时控制台的打印顺序为 App 渲染 → Com 渲染 → useLayoutEffect 执行… → App componentDidMount → useEffect 执行…。

而点击按钮更改状态触发重渲染时,打印顺序为 App 渲染 → Com 渲染 → useLayoutEffect 销毁… → useLayoutEffect 执行… → App componentDidUpdate → useEffect 销毁… → useEffect 执行…。

总结下就是useLayoutEffect 的执行时机要早于 useEffect,useLayoutEffect的执行在类组件生命周期前,useEffect 的执行在类组件生命周期后,官方的建议是要求我们尽量使用useEffect,以避免阻塞视觉更新,如果是将代码从类组件重构为 React Hooks,并且使用 useEffect出现问题,再考虑使用 useLayoutEffect,服务端渲染时使用useLayoutEffect 会触发警告。

你可能感兴趣的:(React,react)