在 React 中使用请求动画帧
Using request animation frame in React
我正在阅读 this article,但不确定我是否理解最后一个钩子的工作原理。
代码如下:
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);
}, []);
}
并以这种方式使用例如:
const [count, setCount] = useState(0);
useAnimationFrame((deltaTime) => {
setCount((prevCount) => {
return prevCount + 1;
});
});
好的,目标是有一个每帧递增的数值。
我可以解释发生了什么运行这段代码:
组件使用 useState(0)
创建本地状态
然后使用此回调作为参数调用 useAnimationFrame
挂钩:
(deltaTime) => {
setCount((prevCount) => {
return prevCount + 1;
});
}
该函数将一个数字作为输入,每次调用时将 ste 状态值递增 1。
useAnimationFrame
是一个将另一个函数作为参数(回调)的函数。它创建了两个引用。在第一次执行时(因为 []
)它调用 useEffect
。它在 requestRef.current
中保存 requestAnimationFrame
returns 的时间戳。 requestRef.current
调用 animate
函数计算请求动画帧(前一个和当前)之间的增量时间,然后使用此值调用回调,因此它调用 setCount
。然后它更新当前的 refs 值并调用 requestAnimationFrame
.
所以循环应该是:
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
我错了吗?
跟踪 requestAnimationFrame
和 cancelAnimationFrame
的函数签名可能会有所帮助。
requestAnimationFrame 接受一个参数,一个回调函数。回调函数本身接收一个时间戳参数 (DOMHighResTimeStamp)
cancelAnimationFrame 接受一个参数,即要取消的 requestAnimationFrame
的 id
。
因此 animate
回调函数中的 time
是通过 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) => {
这是检查挂钩是否已经 运行 1x。如果有,用新时间减去之前的时间更新父 React 作用域
if (previousTimeRef.current !== undefined) {
const deltaTime = time - previousTimeRef.current;
callback(deltaTime);
}
确认钩子有 运行 后,保存 DOMHighResTimeStamp
以备将来计算
previousTimeRef.current = time;
在此之后,它变得有点有趣,我不确定这是最好的方法。它甚至可能是一个错误。该代码设置了一个新的侦听器,并根据新调用的结果使用最新的 ID 更新 ref
。
仅通过阅读代码,我不确定原始侦听器是否得到 cancelled
。我怀疑不是。
/// this is an id
requestRef.current = requestAnimationFrame(animate);
我无法访问 运行ning 版本,但我建议完全删除 requestRef.current
并查看在 useEffect
时是否按预期进行清理清理发生,例如
useEffect(() => {
const id = requestAnimationFrame(animate);
return () => cancelAnimationFrame(id);
}, []);
这也将简化嵌入式 refs
以及使阅读更清晰。
我正在阅读 this article,但不确定我是否理解最后一个钩子的工作原理。
代码如下:
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);
}, []);
}
并以这种方式使用例如:
const [count, setCount] = useState(0);
useAnimationFrame((deltaTime) => {
setCount((prevCount) => {
return prevCount + 1;
});
});
好的,目标是有一个每帧递增的数值。
我可以解释发生了什么运行这段代码:
组件使用
创建本地状态useState(0)
然后使用此回调作为参数调用
useAnimationFrame
挂钩:(deltaTime) => { setCount((prevCount) => { return prevCount + 1; }); }
该函数将一个数字作为输入,每次调用时将 ste 状态值递增 1。
useAnimationFrame
是一个将另一个函数作为参数(回调)的函数。它创建了两个引用。在第一次执行时(因为[]
)它调用useEffect
。它在requestRef.current
中保存requestAnimationFrame
returns 的时间戳。requestRef.current
调用animate
函数计算请求动画帧(前一个和当前)之间的增量时间,然后使用此值调用回调,因此它调用setCount
。然后它更新当前的 refs 值并调用requestAnimationFrame
.
所以循环应该是:
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
我错了吗?
跟踪 requestAnimationFrame
和 cancelAnimationFrame
的函数签名可能会有所帮助。
requestAnimationFrame 接受一个参数,一个回调函数。回调函数本身接收一个时间戳参数 (DOMHighResTimeStamp)
cancelAnimationFrame 接受一个参数,即要取消的 requestAnimationFrame
的 id
。
因此 animate
回调函数中的 time
是通过 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) => {
这是检查挂钩是否已经 运行 1x。如果有,用新时间减去之前的时间更新父 React 作用域
if (previousTimeRef.current !== undefined) {
const deltaTime = time - previousTimeRef.current;
callback(deltaTime);
}
确认钩子有 运行 后,保存 DOMHighResTimeStamp
以备将来计算
previousTimeRef.current = time;
在此之后,它变得有点有趣,我不确定这是最好的方法。它甚至可能是一个错误。该代码设置了一个新的侦听器,并根据新调用的结果使用最新的 ID 更新 ref
。
仅通过阅读代码,我不确定原始侦听器是否得到 cancelled
。我怀疑不是。
/// this is an id
requestRef.current = requestAnimationFrame(animate);
我无法访问 运行ning 版本,但我建议完全删除 requestRef.current
并查看在 useEffect
时是否按预期进行清理清理发生,例如
useEffect(() => {
const id = requestAnimationFrame(animate);
return () => cancelAnimationFrame(id);
}, []);
这也将简化嵌入式 refs
以及使阅读更清晰。