如何控制这个动画计数器的速度



我使用效果挂钩和setTimeout制作了一个非常简单的动画计数器。到目前为止,除了速度外,一切都很好。

如果同一页上有多个计数器,我希望无论最终计数如何,它们都能同时完成动画。我认为在超时时使用计算speed / count会起作用,但这似乎只是随机的。

const Counter = ({ count, speed }) => {
const timeout = useRef();
const [counter, setCounter] = useState(0);

useEffect(() => {
if(counter > 0) {
setCounter(0);
timeout.current = null;
}
}, [count]);

useLayoutEffect(() => {
if(counter < count) {
timeout.current = setTimeout(() => {
setCounter(prev => prev + 1)
}, speed / count);
}

return () => {
if(timeout.current) clearTimeout(timeout.current);
}
});

return (
<div id="counter">
{Intl.NumberFormat('en-EN').format(counter)}
</div>
);
}

我认为这是因为无法预测的重新渲染时间,但我不确定。这是一个带控件的CodePen。

如何控制计数器的速度

我终于找到了解决方案!

计数器不尊重速度,只是因为我试图一个接一个地递增计数器。这意味着,如果我的计数是10000,速度是3000,我要求在3秒内进行10000次渲染,这是不可能的。所以计数器正以最大速度运行。

为了解决这个问题,我将开始时间存储在ref中,然后根据经过的时间进行计算,以知道当前数字应该是多少。我还使用固定时间50作为超时。我想我可以把它作为一个道具来调节它的重复次数。

const Counter = ({ count, speed }) => {
const timer = useRef({ start: Date.now() });
const [counter, setCounter] = useState(0);

useEffect(() => {
if(counter > 0) {
timer.current.start = Date.now();
setCounter(0);
}
}, [count]);

useLayoutEffect(() => {
if(counter < count) {
const timeElapsed  = Date.now() - timer.current.start;
const timePerNum = speed / count;   
const currentCount = Math.round(timeElapsed / timePerNum);

let newCount = currentCount + 1;
if(newCount > count) newCount = count;

setTimeout(() => {
setCounter(newCount)
}, 50);
}
});

return (
<div id="counter">
{Intl.NumberFormat('en-EN').format(counter)}
</div>
);
}

我已经用修复程序更新了CodePen。

最新更新