React Hook - detailed explanation of useEffecfa function

Detailed analysis of useEffect

useEffecf basic use

The book continues from the above. In the previous article, we explained the State Hook. We can use this hook to define state in functional components.

We know that there can be lifecycle functions in class components, so how to define functions similar to lifecycle in function components?

Effect Hook allows you to complete some functions similar to the life cycle in class;

In fact, similar to network requests, manual updating of DOM, and monitoring of some events are some side effects (Side Effects) of React updating DOM;

So the Hook that completes these functions is called Effect Hook;

Suppose we now have a requirement: the title on the page always displays the number of the counter, which is implemented using class components and Hook respectively :

Class component implementation

import React, {
    
     PureComponent } from 'react'

export class App extends PureComponent {
    
    
  constructor() {
    
    
    super()

    this.state = {
    
    
      counter: 100
    }
  }

  // 进入页面时, 标题显示counter
  componentDidMount() {
    
    
    document.title = this.state.counter
  }

  // 数据发生变化时, 让标题一起变化
  componentDidUpdate() {
    
    
    document.title = this.state.counter
  }

  render() {
    
    
    const {
    
     counter } = this.state

    return (
      <div>
        <h2>{
    
    counter}</h2>
        <button onClick={
    
    () => this.setState({
    
    counter: counter+1})}>+1</button>
      </div>
    )
  }
}

export default App

Implementation of function component plus Hook:

  • Through the useEffect Hook, you can tell React that you need to perform certain operations after rendering;
  • useEffect requires us to pass in a callback function, which will be called back after React finishes updating the DOM ( that is, after the component is rendered );
  • 默认情况下, whether it is after the first rendering or after each update, this callback function will be executed; in general, we write side effects in this callback function (such as network requests, DOM operations, event monitoring )

Therefore, it should be noted that there are many sayings that useEffect is used to simulate the life cycle, but it is not; useEffect can simulate the life cycle, but its main function is to perform side effects

import React, {
    
     memo, useEffect, useState } from 'react'

const App = memo(() => {
    
    
  const [counter, setCounter] = useState(200)

  // useEffect传入一个回调函数, 在页面渲染完成后自动执行
  useEffect(() => {
    
    
    // 一般在该回调函数在编写副作用的代码(网络请求, 操作DOM, 事件监听)
    document.title = counter
  })

  return (
    <div>
      <h2>{
    
    counter}</h2>
      <button onClick={
    
    () => setCounter(counter+1)}>+1</button>
    </div>
  )
})

export default App

Clear side effects (Effect)

In the process of writing class components, some side-effect codes need to be cleared in componentWillUnmount :

For example, manually call subscribe in our previous event bus or Redux;

All need to have a corresponding unsubscribe in componentWillUnmount;

How does Effect Hook simulate componentWillUnmount?

The useEffect passed in 回调函数Aitself can have a return value, which is another回调函数B :

type EffectCallback = () => (void | (() => void | undefined));

Why return a function in effect?

This is an optional cleanup mechanism for effects. Each effect can return a cleanup function;

So you can 添加和移除put the subscription logic together;

They are all part of effect;

When does React clear the effect?

React will perform a cleanup operation when the component is updated and uninstalled, canceling the last monitoring, leaving only the current monitoring;

As learned before, effects are executed on every render;

import React, {
    
     memo, useEffect } from 'react'

const App = memo(() => {
    
    
  useEffect(() => {
    
    
    // 监听store数据发生改变
    const unsubscribe = store.subscribe(() => {
    
    

    })

    // 返回值是一个回调函数, 该回调函数在组件重新渲染或者要卸载时执行
    return () => {
    
    
      // 取消监听操作
      unsubscribe()
    }
  })

  return (
    <div>
      <h2>App</h2>
    </div>
  )
})

export default App

Using multiple useEffects

One of the purposes of using Hook is to solve the problem that the life cycle of a class often puts a lot of logic together :

For example, network requests, event monitoring, and manual modification of DOM are often placed in componentDidMount;

Multiple Effect Hooks can be used in a function component, and we can separate the logic into different useEffects :

import React, {
    
     memo, useEffect } from 'react'

const App = memo(() => {
    
    
  // 监听的useEffect
  useEffect(() => {
    
    
    console.log("监听的代码逻辑")

    return () => {
    
    
      console.log("取消的监听代码逻辑")
    }
  })

  // 发送网络请求的useEffect
  useEffect(() => {
    
    
    console.log("网络请求的代码逻辑")
  })

  // 操作DOM的useEffect
  useEffect(() => {
    
    
    console.log("操作DOM的代码逻辑")
  })

  return (
    <div>
      App
    </div>
  )
})

export default App

Hook allows us to separate them according to the purpose of the code, instead of putting a lot of logic together like a lifecycle function :

依次调用React will follow each effect in the component in the order of effect declaration ;


useEffect performance optimization

By default, useEffect's callback function will be re-executed every time it is rendered, but this will cause two problems :

Some codes we just want to execute once ( such as network requests, execute once in the first rendering of components, do not need to execute multiple times ), similar to what is done in componentDidMount and componentWillUnmount in class components;

In addition, multiple executions will also cause certain performance problems;

How do we decide when useEffect should execute and when it should not execute?

useEffect actually has two parameters:

  • Parameter 1: The callback function to be executed, we have already used this parameter and will not say more;
  • Parameter 2: It is an array type, which means that the useEffect will be re-executed when the state changes; ( who will be affected by who will be re-executed )

Case exercises :

Effect affected by count;

import React, {
    
     memo, useEffect, useState } from 'react'

const App = memo(() => {
    
    
  const [counter, setCounter] = useState(100)
  
  // 发送网络请求的useEffect, 只有在counter发生改变时才会重新执行
  useEffect(() => {
    
    
    console.log("网络请求的代码逻辑")
  }, [counter])

  return (
    <div>
      <h2 onClick={
    
    () => setCounter(counter+1)}>{
    
    counter}</h2>
    </div>
  )
})

export default App

However, if a function we 不希望依赖任何的内容时can also pass in an empty array [] :

Then the two callback functions here correspond to the componentDidMount and componentWillUnmount lifecycle functions respectively;

import React, {
    
     memo, useEffect, useState } from 'react'

const App = memo(() => {
    
    
  const [counter, setCounter] = useState(100)
  
  // 传入空数组表示不受任何数据依赖
  useEffect(() => {
    
    
    // 此时传入的参数一这个回调函数: 相当于componentDidMount
    console.log("监听的代码逻辑")

    // 参数一这个回调函数的返回值: 相当于componentWillUnmount
    return () => {
    
    
      console.log("取消的监听代码逻辑")
    }
  }, [])

  return (
    <div>
      <h2 onClick={
    
    () => setCounter(counter+1)}>{
    
    counter}</h2>
    </div>
  )
})

export default App

Summary: useEffect can simulate the life cycle of the previous class component ( similar but not equal ), and it is more powerful than the original life cycle, blue is better than blue

Guess you like

Origin blog.csdn.net/m0_71485750/article/details/126840653