React useRequestAnimationFrame钩子

在每次重绘之前运行一个动画函数。

  • 使用useRef()钩子创建两个变量。requestRef将保存最后一个请求的ID,previousTimeRef将保存最后一个时间戳。
  • 定义一个函数animate,用于更新这些变量,运行callback并持续调用Window.requestAnimationFrame()
  • 使用带有空数组的useEffect()钩子,使用Window.requestAnimationFrame()初始化requestRef的值。使用返回的值和Window.cancelAnimationFrame()在组件卸载时进行清理。
const useRequestAnimationFrame = callback => {
  const requestRef = React.useRef();
  const previousTimeRef = React.useRef();

  const animate = time => {
    if (previousTimeRef.current) callback(time - previousTimeRef.current);
    previousTimeRef.current = time;
    requestRef.current = requestAnimationFrame(animate);
  };

  React.useEffect(() => {
    requestRef.current = requestAnimationFrame(animate);
    return () => cancelAnimationFrame(requestRef.current);
  }, []);
};

const Counter = () => {
  const [count, setCount] = React.useState(0);

  useRequestAnimationFrame(deltaTime => {
    setCount(prevCount => (prevCount + deltaTime * 0.01) % 100);
  });

  return <p>{Math.round(count)}</p>;
};

ReactDOM.createRoot(document.getElementById('root')).render(
  <Counter />
);