gpt4 book ai didi

javascript - useAnimationOnDidUpdate react 钩子(Hook)实现

转载 作者:行者123 更新时间:2023-12-03 14:22:13 25 4
gpt4 key购买 nike

所以我想使用 requestAnimationFrame 使用 react 钩子(Hook)来制作动画。
我想要一些小东西,所以 react-spring/animated/react-motion 对我来说是一个糟糕的选择。
我实现了 useAnimationOnDidUpdate 但它工作不正确,这里是 reproduction有详细信息。
这里有什么问题:第二次点击动画的乘数从 1 开始,但应该始终从 0 开始(从 0 到 1 的简单插值)。
所以我试图理解为什么钩子(Hook)保存了以前的值,尽管我已经开始了一个新的动画循环。
这是钩子(Hook)的完整代码 list :

import { useState, useEffect, useRef } from 'react';

export function useAnimationOnDidUpdate(
easingName = 'linear',
duration = 500,
delay = 0,
deps = []
) {
const elapsed = useAnimationTimerOnDidUpdate(duration, delay, deps);
const n = Math.min(1, elapsed / duration);

return easing[easingName](n);
}

// https://github.com/streamich/ts-easing/blob/master/src/index.ts
const easing = {
linear: n => n,
elastic: n =>
n * (33 * n * n * n * n - 106 * n * n * n + 126 * n * n - 67 * n + 15),
inExpo: n => Math.pow(2, 10 * (n - 1)),
inOutCubic: (t) => t <.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
};

export function useAnimationTimerOnDidUpdate(duration = 1000, delay = 0, deps = []) {
const [elapsed, setTime] = useState(0);
const mountedRef = useRef(false);

useEffect(
() => {
let animationFrame, timerStop, start, timerDelay;

function onFrame() {
const newElapsed = Date.now() - start;

setTime(newElapsed);
if (newElapsed >= duration) {
console.log('>>>> end with time', newElapsed)
return;
}
loop();
}

function loop() {
animationFrame = requestAnimationFrame(onFrame);
}

function onStart() {
console.log('>>>> start with time', elapsed)
start = Date.now();
loop();
}

if (mountedRef.current) {
timerDelay = delay > 0 ? setTimeout(onStart, delay) : onStart();
} else {
mountedRef.current = true;
}

return () => {
clearTimeout(timerStop);
clearTimeout(timerDelay);
cancelAnimationFrame(animationFrame);
};
},
[duration, delay, ...deps]
);

return elapsed;
}

最佳答案

此 Hook 的问题是它在完成后不会清理 elapsedTime

当动画预计停止时,您可以通过将 setTime(0) 添加到 onFrame 函数来解决此问题。

像这样:

function onFrame() {
const newElapsed = Date.now() - start;

if (newElapsed >= duration) {
console.log('>>>> end with time', newElapsed)
setTime(0)
return;
}

setTime(newElapsed);
loop();
}

我知道它不会自行重置可能看起来很奇怪。但请记住,您的动画使用相同的钩子(Hook)实例来进行缓入和缓出。因此清理是必要的。

注意:我还移动了 setTime(newElapsed) 行,使其位于 if 语句之后,因为如果 if 陈述是正确的。

更新:

要进一步改进其工作方式,您可以将 setTime(0) 移至 return 清理。

这意味着您的 onFrame 函数更改为:

function onFrame() {
const newElapsed = Date.now() - start;

if (newElapsed >= duration) {
console.log('>>>> end with time', newElapsed)
setTime(0)
return;
}

setTime(newElapsed);
loop();
}

然后将 useAnimationTimerOnDidUpdatereturn 清理更新为:

return () => {
clearTimeout(timerStop);
clearTimeout(timerDelay);
cancelAnimationFrame(animationFrame);
setTime(0);
};

我假设您的动画“无法正常工作”的原因是该组件会闪烁。就我的测试而言,此更新修复了该问题。

关于javascript - useAnimationOnDidUpdate react 钩子(Hook)实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60967303/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com