I'am tring to build a number-reaseing animation in a component ,and i use useRef to save my timer,and use a state to show the number changes .So the number absolutly changed ,but it can worked also after the number passed the number i set as 100;I checked the timer-ID and it didn't be changed,but the timer-clear didn't work.This is my code;
import { useCallback, useRef, useState } from "react";
interface Props {
num: number
}
const AnimateP: React.FC<Props> = (props) => {
const [num, setNum] = useState(0);
const numAdd = useCallback(() => {
const temp = num;
setNum(temp 1)
if(temp>props.num) {
console.log("clearTimeout",_timer.current)
console.log(_timer,"_timer")
clearTimeout(_timer.current)
}
}, [num])
const _timer = useRef<NodeJS.Timer>(
setTimeout(() => {
numAdd()
}, 100)
)
return (
<div style={{ width: "100%", backgroundColor: "#000", color: "#fff" }}>{num}</div>
)
}
export default AnimateP;[enter image description here][1]
CodePudding user response:
You should avoid running any code with side-effects inside of callback function passed to useRef
. Instead, use useEffect
to start the loop, and then fire your function recursively from within itself:
import { useCallback, useRef, useState } from "react";
interface Props {
num: number;
}
const AnimateP: React.FC<Props> = (props) => {
const [num, setNum] = useState(0);
const numAdd = useCallback(() => {
const temp = num;
setNum(temp 1);
if (temp > props.num) {
console.log("break the loop of recursion");
return;
}
setTimeout(numAdd, 100);
}, [props.num, num]);
useEffect(() => {
setTimeout(numAdd, 100);
}, [numAdd]);
return <div style={{ width: "100%", backgroundColor: "#000", color: "#fff" }}>{num}</div>;
};
CodePudding user response:
useRef don't support lazy initianization. You passed in setTimeout()
as parammeter. It will be called at every rendering. You will set many timeout, but only last one will modify your num
. Your clearTimeout can only delete the first one.