'react - using setInterval in a useCallback function that is called more than once
I'm trying to do the following
- On
isAnimate: booleanstate change, determine if triggeranimate()ordraw()draw()works fine
- I also need a button to reset the animation, which is handled with the state
toReset: boolean.- When
toResetis true, immediately settoResettofalseand callanimate()
- When
- The animation is just an SVG with a single
<path>element with itsdattribute changed constantly.
Here are the functions that are of relevance (in source code writing order):
// Animation function (the problem function)
const animate = useCallback(() => {
console.log("animation start");
clearSVGPath(pathElement.current);
scaleSVGToPaths(svgElement.current, paths);
function* generatorPath() {
for (const path of paths) {
yield path;
}
}
const gen = generatorPath();
const animationTickTime = animationSpeed < 50 ? 1000 / animationSpeed : 20;
const animationTickPaths =
animationSpeed < 50 ? 1 : Math.round((20 * animationSpeed) / 1000);
console.log("tick time: ", animationTickTime);
console.log("tick lines: ", animationTickPaths);
clearInterval(animationIntervalID.current);
console.log("cleared animation interval ID: ", animationIntervalID.current);
function onTick() {
console.log("interval start");
let { value, done } = gen.next();
let i = 1;
const values = [];
while (i < animationTickPaths && !done) {
values.push(value);
({ value, done } = gen.next());
i += 1;
}
if (value) {
values.push(value);
}
console.log(values);
addPathsToSVG(pathElement.current, values);
if (done) {
clearInterval(animationIntervalID.current);
console.log("done");
}
}
console.log("starting interval");
animationIntervalID.current = setInterval(onTick, animationTickTime);
console.log("set: animation interval ID: ", animationIntervalID.current);
}, [animationSpeed, paths]);
// Draw Instantly
const draw = useCallback(() => {
clearSVGPath(pathElement.current);
scaleSVGToPaths(svgElement.current, paths);
setSVGPaths(pathElement.current, paths);
}, [paths]);
// reset animation
useEffect(() => {
if (!toReset) {
return;
}
setToReset(false);
animate();
return () => clearInterval(animationIntervalID.current);
}, [toReset, animate, setToReset]);
// Decide whether to draw instantly or animate
useEffect(() => {
if (!system) {
return;
}
if (!isAnimate) {
draw();
return;
}
animate();
return () => clearInterval(animationIntervalID.current);
}, [isAnimate, system, animate, draw]);
The problem: Upon change of isAnimate -> true (fourth codeblock, then first codeblock happens), it is all fine. However, upon toReset -> true, the animate() function is called but setInterval doesn't work correctly, even if cleared beforehand. Sometimes onTick() only runs one time before not working again, sometimes onTick() doesn't run at all.
A console screenshot after isAnimate -> true and then toReset -> true:
console screenshot
I'm not really sure what causes this problem, and would like assistance.
Thanks.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
