react挂钩中的useEffect执行顺序及其内部清理逻辑是什么?

根据反应文件,useEffect它将在重新运行useEffect部分之前触发清理逻辑。

如果您的效果返回一个函数,React将在需要清理时运行它。

没有处理更新的特殊代码,因为useEffect默认情况下会处理更新。它会在应用下一个效果之前清理上一个效果…

但是,当我在requestAnimationFramecancelAnimationFrame内部使用时useEffect,我发现cancelAnimationFrame可能无法正常停止动画。有时,我发现旧动画仍然存在,而下一个效果带来了另一个动画,这导致了我的Web应用程序性能问题(尤其是当我需要渲染沉重的DOM元素时)。

我不知道React钩子是否会在执行清理代码之前做一些额外的事情,这会使我的取消动画部分无法正常工作,useEffect钩子是否会像闭包那样锁定状态变量?

useEffect的执行顺序及其内部清理逻辑是什么?我在下面编写的代码有什么问题,这使cancelAnimationFrame无法完美运行吗?

谢谢。

//import React, { useState, useEffect } from "react";

const {useState, useEffect} = React;

//import ReactDOM from "react-dom";

function App() {

const [startSeconds, setStartSeconds] = useState(Math.random());

const [progress, setProgress] = useState(0);

useEffect(() => {

const interval = setInterval(() => {

setStartSeconds(Math.random());

}, 1000);

return () => clearInterval(interval);

}, []);

useEffect(

() => {

let raf = null;

const onFrame = () => {

const currentProgress = startSeconds / 120.0;

setProgress(Math.random());

// console.log(currentProgress);

loopRaf();

if (currentProgress > 100) {

stopRaf();

}

};

const loopRaf = () => {

raf = window.requestAnimationFrame(onFrame);

// console.log('Assigned Raf ID: ', raf);

};

const stopRaf = () => {

console.log("stopped", raf);

window.cancelAnimationFrame(raf);

};

loopRaf();

return () => {

console.log("Cleaned Raf ID: ", raf);

// console.log('init', raf);

// setTimeout(() => console.log("500ms later", raf), 500);

// setTimeout(()=> console.log('5s later', raf), 5000);

stopRaf();

};

},

[startSeconds]

);

let t = [];

for (let i = 0; i < 1000; i++) {

t.push(i);

}

return (

<div className="App">

<h1>Hello CodeSandbox</h1>

<text>{progress}</text>

{t.map(e => (

<span>{progress}</span>

))}

</div>

);

}

ReactDOM.render(<App />,

document.querySelector("#root"));

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0-alpha.2/umd/react.production.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0-alpha.2/umd/react-dom.production.min.js"></script>

<div id="root"></div>

回答:

将这三行代码放入组件中,您将看到它们的优先顺序。

  useEffect(() => {

console.log('useEffect')

return () => {

console.log('useEffect cleanup')

}

})

window.requestAnimationFrame(() => console.log('requestAnimationFrame'))

useLayoutEffect(() => {

console.log('useLayoutEffect')

return () => {

console.log('useLayoutEffect cleanup')

}

})

useLayoutEffect > requestAnimationFrame > useEffect

您遇到的问题是由执行loopRaf清理功能之前请求另一个动画帧引起的useEffect

进一步的测试表明,该useLayoutEffect操作始终在之前被调用,requestAnimationFrame并且其清理功能在下一次执行之前被调用,以防止重叠。

更改useEffectuseLayoutEffect,它应该可以解决您的问题。

useEffectuseLayoutEffect按照它们在代码中出现的顺序调用,就像useState调用一样。

您可以通过运行以下几行来查看:

  useEffect(() => {

console.log('useEffect-1')

})

useEffect(() => {

console.log('useEffect-2')

})

useLayoutEffect(() => {

console.log('useLayoutEffect-1')

})

useLayoutEffect(() => {

console.log('useLayoutEffect-2')

})

以上是 react挂钩中的useEffect执行顺序及其内部清理逻辑是什么? 的全部内容, 来源链接: utcz.com/qa/429846.html

回到顶部