useEffect的回调的return语句何时执行? [英] When does the useEffect's callback's return statement execute?

查看:508
本文介绍了useEffect的回调的return语句何时执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想澄清一下我对这里发生的事情的理解.任何可以增进我当前理解的细节都将受到赞赏.

I'd like to clarify my understanding of what's happening here. Any detail to improve my current understanding'd be appreciated.

function Timer() {

    let [time, setTime] = useState(5);

    useEffect(() => {
        let timer = setInterval(() => {
          setTime(time - 1);
        }, 1000)
        return () => clearInterval(timer);
    }, );

    return <div>{time}</div>
}

export default Timer

https://codesandbox.io/s/cranky-chaplygin-g1r0p

  1. 时间被初始化为 5 .
  2. 读取
  3. useEffect .必须准备好其回调,以便稍后触发.
  4. 呈现 div .
  5. useEffect 的回调已执行. setInterval 的回调已准备好启动.当然, useEffect return 语句不会在此处触发,因为如果这样做,它将取消计时器(计时器确实起作用).
  6. 大约1秒钟后,触发 setInterval 的回调将更改 time 的状态(更改为4).
  7. 现在状态已更改,该功能将重新执行. time (一个新变量)被初始化为新的时间状态.
  8. 读取一个新的 useEffect ,它的回调函数准备在以后启动.(这是因为没有 useEffect()的第二个参数).
  9. 执行组件函数的 return 语句.这样可以有效地重新呈现 div .
  10. 在某个时候,将执行先前的 useEffect return 语句(这将在先前的 useEffect 中禁用 timer 代码>).我不确定何时会发生这种情况.
  11. 'new' useEffect 的回调已执行.
  1. time is being initialised to 5.
  2. useEffect is read. Its callback must be made ready to fire later.
  3. The div is rendered.
  4. useEffect's callback is executed. setInterval's callback gets ready to fire. Surely useEffect's return statement doesn't fire here, because if it did it would cancel the timer (and the timer does work).
  5. After, roughly, 1 second, setInterval's callback fires changing the state of time (to 4).
  6. Now that a piece of state has changed, the function is re-executed. time, a new variable, is initialised to the new time state.
  7. A new useEffect is read, it's callback made ready to fire later. (This happens because there is no 2nd argument of useEffect()).
  8. The component function's return statement is executed. This effectively re-renders the div.
  9. At some point, the previous useEffect's return statement executes (which disables the timer in that previous useEffect). I'm not sure when this occurs.
  10. The 'new' useEffect's callback is executed.

推荐答案

您对事件顺序的理解是正确的.唯一缺少的是效果回调和清理的准确时间.

Your understanding of the sequence of events is correct. The only thing missing is the precise timing of the effect callbacks and cleanup.

重新渲染组件时,将对所有 useEffect 的依赖项数组进行分析以进行更改.如果进行了更改,则将运行该效果回调.保证这些回调按照在组件中声明的顺序运行.例如,在下面, a 将始终记录在 b 之前.

When the component re-renders, any useEffects will have their dependency arrays analyzed for changes. If there has been a change, then that effect callback will run. These callbacks are guaranteed to run in the order that they're declared in the component. For example, below, a will always be logged just before b.

const App = () => {
    const [num, setNum] = React.useState(0);
    React.useEffect(() => {
      setInterval(() => {
        setNum(num => num + 1);
      }, 1000);
    }, []);
    React.useEffect(() => {
      console.log('a', num);
    }, [num]);
    React.useEffect(() => {
      console.log('b', num);
    }, [num]);
    return num;
}

ReactDOM.render(<App />, document.querySelector('.react'));

<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>

这些效果回调将在浏览器重新绘制后不久运行.

These effect callbacks will run shortly after the browser re-paints.

现在将效果清理回调添加到混合中.这些将始终在渲染运行的效果回调之前 同步运行.例如,假设组件从渲染A开始,而在渲染A中,效果挂钩返回了清理回调.然后,一些状态发生变化,并且发生了向渲染器B的过渡,并且存在一个 useEffect ,其依赖项数组包括状态更改.将会发生什么:

Now add the effect cleanup callback into the mix. These will always run synchronously just before the effect callback for a render runs. For example, let's say the component starts at Render A, and in Render A, an effect hook has returned a cleanup callback. Then, some state changes, and a transition to Render B occurs, and there exists a useEffect with a dependency array that includes the state change. What will happen is:

  • 对于渲染B,功能组件将使用新的props/state进行调用
  • 该组件在函数末尾返回新的标记
  • 必要时浏览器会重新粉刷屏幕
  • 渲染A的清理功能将运行
  • 渲染B的效果回调将运行
  • The functional component will be called with the new props/state, for Render B
  • The component returns the new markup at the end of the function
  • The browser repaints the screen if necessary
  • The cleanup function from render A will run
  • The effect callback from render B will run

您可以查看最后两个操作的源代码

You can see the source code for those last two actions here:

commitHookEffectListUnmount(Passive$1 | HasEffect, finishedWork);
commitHookEffectListMount(Passive$1 | HasEffect, finishedWork);

第一个调用从先前的渲染调用所有清理回调.第二个调用调用当前渲染的所有效果回调.当前的渲染效果回调在先前的渲染清理回调执行之后同步运行.

That first call invokes all cleanup callbacks from a prior render. That second call invokes all effect callbacks for the current render. Current render effect callbacks run synchronously after the execution of prior render cleanup callbacks.

这篇关于useEffect的回调的return语句何时执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆