mar*_*lle 7 javascript requestanimationframe reactjs
我正在阅读这篇文章,但不确定我是否理解最终的钩子是如何工作的。
这是代码:
const useAnimationFrame = (callback) => {
const requestRef = useRef();
const previousTimeRef = useRef();
const animate = (time) => {
if (previousTimeRef.current !== undefined) {
const deltaTime = time - previousTimeRef.current;
callback(deltaTime);
}
previousTimeRef.current = time;
requestRef.current = requestAnimationFrame(animate);
};
useEffect(() => {
requestRef.current = requestAnimationFrame(animate);
return () => cancelAnimationFrame(requestRef.current);
}, []);
}
Run Code Online (Sandbox Code Playgroud)
并以这种方式使用例如:
const [count, setCount] = useState(0);
useAnimationFrame((deltaTime) => {
setCount((prevCount) => {
return prevCount + 1;
});
});
Run Code Online (Sandbox Code Playgroud)
好吧,目标是有一个每帧递增的数值。
我可以解释运行这段代码会发生什么:
该组件创建一个本地状态useState(0)
然后useAnimationFrame使用此回调作为参数调用钩子:
(deltaTime) => {
setCount((prevCount) => {
return prevCount + 1;
});
}
Run Code Online (Sandbox Code Playgroud)
该函数将一个数字作为输入,并在每次调用时将 ste 状态值递增 1。
useAnimationFrame是一个接受另一个函数作为参数的函数(回调)。它创建了两个引用。第一次执行时(因为[])它调用useEffect. 它将返回的requestRef.current时间戳保存在时间戳中requestAnimationFrame。调用计算请求动画帧(前一个和当前)之间的增量时间的函数,然后使用该值调用回调,以便它requestRef.current调用. 然后它更新当前的 refs 值并调用.animatesetCountrequestAnimationFrame所以循环应该是:
component
> count = 0
useAnimationFrame <--------------+
> requestRef = ? |
> previousTimeRef = ? |
useEffect |
animate |
> deltaTime = delta#1 |
> count = 1 |
> previousTimeRef.current = time#1 |
> requestRef.current = time#2 -------+
> requestRef.current = timestamp#1
Run Code Online (Sandbox Code Playgroud)
我错了吗?
跟踪requestAnimationFrame和的函数签名可能会有所帮助cancelAnimationFrame。
requestAnimationFrame采用单个参数,即回调函数。回调函数本身接收单个时间戳参数 (DOMHighResTimeStamp)
cancelAnimationFrame采用一个参数,即id您requestAnimationFrame要取消的动画。
所以回调函数time中animate是通过 api 接收到的单个参数,a DOMHighResTimeStamp similar to the one returned by performance.now(), indicating the point in time when requestAnimationFrame() starts to execute callback functions.
const animate = (time) => {
Run Code Online (Sandbox Code Playgroud)
这是检查挂钩是否已运行 1x 次。如果有,则用新时间减去上一个时间来更新父 React 范围
if (previousTimeRef.current !== undefined) {
const deltaTime = time - previousTimeRef.current;
callback(deltaTime);
}
Run Code Online (Sandbox Code Playgroud)
一旦确认挂钩已运行,请保存DOMHighResTimeStamp以供将来计算
previousTimeRef.current = time;
Run Code Online (Sandbox Code Playgroud)
之后,它变得有点有趣,我不确定这是最好的方法。它甚至可能是一个错误。该代码设置一个新的侦听器,并ref根据新调用的结果使用最新的 id 进行更新。
仅通过阅读代码,我不确定原始侦听器是否会得到cancelled. 我怀疑事实并非如此。
/// this is an id
requestRef.current = requestAnimationFrame(animate);
Run Code Online (Sandbox Code Playgroud)
我无权访问正在运行的版本,但我建议requestRef.current完全删除并查看清理发生时是否按预期进行,useEffect例如
useEffect(() => {
const id = requestAnimationFrame(animate);
return () => cancelAnimationFrame(id);
}, []);
Run Code Online (Sandbox Code Playgroud)
这也将简化嵌入refs,使阅读更加清晰。
| 归档时间: |
|
| 查看次数: |
7153 次 |
| 最近记录: |