The code execution order inside and outside return when useEffect has dependencies and no dependencies

A problem was encountered in a recent project. The timer is called once a second to request data, and the timer is cleared when the number reaches the total number. Because sometimes the interface will fail to call, so the timer cannot be stopped if the total number is not reached, and the current page cannot be stopped even if it is closed to other pages. . So there needs to be a closing page to clear the timer operation, so I thought of the return of the first function parameter of useEffect.

1. The basic usage of useEffect

useEffect receives two parameters, the first parameter is the Effect function; the second parameter is an array to avoid unnecessary repeated calls of effects; the second parameter of useEffect is
used to define dependent variables, if an empty array is passed, that is, there is no dependent change item, it will only be called once when the page is initialized, if a dependency is added, the change of one of the variables in the dependent array will trigger the execution; when the second parameter does not exist, the function of the first parameter of useEffect will be executed every time the page is updated; for
example
:

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

function Demo () {
  const [count,setCount]=useState(0)
  useEffect(() => { 
    console.log('无依赖---------------------------',count)
  })
  useEffect(() => { 
    console.log('依赖为[]------------------------',count)
  },[])
  useEffect(() => { 
    console.log('依赖为[count]------------------------',count)
  },[count])
  return (
    <div>
      <p>count的值为: {count} </p>
      <button onClick={()=>setCount(count+1)}>add</button>
    </div>
  )
}

export default Demo

Initialize the execution result:

无依赖--------------------------- 0
About.tsx:9 依赖为[]------------------------ 0
About.tsx:12 依赖为[count]------------------------ 0

The result after clicking add:

无依赖--------------------------- 1
About.tsx:12 依赖为[count]------------------------ 1

Two, return a function in useEffect

Regarding the return return value of the first function parameter of useEffect():

Side effects occur when the component is loaded, so when the component is unloaded, these side effects may need to be cleaned up.
useEffect() allows to return a function that is executed when the component is unmounted to clean up side effects. If you don't need to clean up side effects, useEffect() doesn't have to return anything.

For a better understanding, let's look at the results first and then summarize, first look at the example supplement:

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

function Demo () {
  const [count,setCount]=useState(0)
  useEffect(() => { 
    console.log('无依赖---------------------------', count)
    return () => {
      console.log('执行  无依赖  时的return的函数')
    }
  })
  useEffect(() => { 
    console.log('依赖为[]------------------------', count)
    return () => {
      console.log('执行 依赖为[]  时的return的函数')
    }
  },[])
  useEffect(() => { 
    console.log('依赖为[count]------------------------', count)
    return () => {
      console.log('执行 依赖为[count]  时的return的函数')
    }
  },[count])
  return (
    <div>
      <p>count的值为: {count} </p>
      <button onClick={()=>setCount(count+1)}>add</button>
    </div>
  )
}

export default Demo

 1. The console prints the result during initialization:

无依赖--------------------------- 0
依赖为[]------------------------ 0
依赖为[count]------------------------ 0
执行  无依赖  时的return的函数
执行 依赖为[]  时的return的函数
执行 依赖为[count]  时的return的函数
无依赖--------------------------- 0
依赖为[]------------------------ 0
依赖为[count]------------------------ 0

It can be seen that each useEffect internal function is executed twice during initialization, because I am using React 18, React 18 will force the component to be updated once in concurrent mode, and each return function is also executed once when the update is forced. It is equivalent to performing the following operations: mount component----remove component-remount component. If it is React 17, it will only be mounted once, and the printed result will be:

无依赖--------------------------- 0
依赖为[]------------------------ 0
依赖为[count]------------------------ 0

2. The console print result after clicking the add button: 

执行  无依赖  时的return的函数
执行 依赖为[count]  时的return的函数
无依赖--------------------------- 1
依赖为[count]------------------------ 1

At this time, the updated variable is count, so the useEffect that listened to the count is executed, and the useEffect without the second parameter is also executed. Every time, the return function is executed first, and then the part outside the return is executed.

3. When switching to other pages (that is, removing components), the console prints the results: 

执行  无依赖  时的return的函数
执行 依赖为[]  时的return的函数
执行 依赖为[count]  时的return的函数

At this time, the return part in it is executed in sequence according to the order of useEffect

Notes on useEffect()

There is one caveat when using useEffect(). If there are multiple side effects, multiple useEffect() should be called instead of merged and written together.

Wrong way:

function App() {
  const [varA, setVarA] = useState(0);
  const [varB, setVarB] = useState(0);
  useEffect(() => {
    const timeoutA = setTimeout(() => setVarA(varA + 1), 1000);
    const timeoutB = setTimeout(() => setVarB(varB + 2), 2000);

    return () => {
      clearTimeout(timeoutA);
      clearTimeout(timeoutB);
    };
  }, [varA, varB]);

  return <span>{varA}, {varB}</span>;
}

The above example is wrongly written. There are two timers in the side effect function, and there is no relationship between them. They are actually two unrelated side effects and should not be written together. The correct way to write them is to separate them into two useEffect().
Correct spelling:

function App() {
  const [varA, setVarA] = useState(0);
  const [varB, setVarB] = useState(0);

  useEffect(() => {
    const timeout = setTimeout(() => setVarA(varA + 1), 1000);
    return () => clearTimeout(timeout);
  }, [varA]);

  useEffect(() => {
    const timeout = setTimeout(() => setVarB(varB + 2), 2000);

    return () => clearTimeout(timeout);
  }, [varB]);

  return <span>{varA}, {varB}</span>;
}

Summarize:

  • When there are no dependencies, the part outside the return of the first parameter function of useEffect will be executed for the first load, and the part inside the return will be executed first, and then the part outside the return will be executed every time it is updated.
  • When the dependency is an empty array ([]), the function of the first parameter of useEffect will be run when the page is first loaded, similar to executing componentDidMount, and only executed once, and the return function in the function will be executed when the page is about to be destroyed or when the component is removed, similar to executing componentWillUnMount
  • When the dependency is not empty, the part outside the return of the first parameter function of useEffect will be executed for the first time loading. Every time the dependency is updated, the part inside the return will be executed first, and then the part outside the return will be executed.

That is to say, except for the initial mounting and removal of components, the functions outside the return and inside the return will be executed separately, and the rest of the functions will be executed in the return and then outside the return.

Original link: https://blog.csdn.net/CX345678/article/details/128705404

Guess you like

Origin blog.csdn.net/BUG_CONQUEROR_LI/article/details/130875148