According to react document, useEffect
will trigger clean-up logic before it re-runs useEffect
part.
If your effect returns a function, React will run it when it is time to clean up...
There is no special code for handling updates because
useEffect
handles them by default. It cleans up the previous effects before applying the next effects...
However, when I use requestAnimationFrame
and cancelAnimationFrame
inside useEffect
, I found the cancelAnimationFrame may not stop the animation normally. Sometimes, I found the old animation still exists, while the next effect brings another animation, which causes my web app performance issues (especially when I need to render heavy DOM elements).
I don't know whether react hook will do some extra things before it executes the clean-up code, which make my cancel-animation part not work well, will useEffect
hook do something like closure to lock the state variable?
What's useEffect's execution order and its internal clean-up logic? Is there something wrong the code I write below, which makes cancelAnimationFrame can't work perfectly?
Thanks.
//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>