Skip to content

Instantly share code, notes, and snippets.

@flamerohr
Last active October 5, 2020 09:30
Show Gist options
  • Select an option

  • Save flamerohr/d70433e8c910d14463631e5fc36ff83f to your computer and use it in GitHub Desktop.

Select an option

Save flamerohr/d70433e8c910d14463631e5fc36ff83f to your computer and use it in GitHub Desktop.
An animation frame hook
import {
useRef, useLayoutEffect,
} from 'react';
const FRAME_RATE = 1000 / 60;
/**
* A react hook for using animation frame, which will cancel when unmounted.
* This was intended for basic drawing logic on a canvas, anything too complex should
* consider using a drawing library instead.
*
* @param {Function} draw - the function handle drawing when the frame is ready,
* a good idea to wrap in `useCallback` so reference only changes when state changes
*/
export const useAnimationFrame = (draw) => {
const drawRef = useRef(draw);
const oldDrawRef = useRef(null);
drawRef.current = draw;
useLayoutEffect(() => {
let prevTime;
let cancelled = false;
async function frame(timestamp) {
if (cancelled) {
return;
}
if (
typeof drawRef.current != 'function'
|| drawRef.current === oldDrawRef.current
|| (prevTime && FRAME_RATE > timestamp - prevTime)
) {
requestAnimationFrame(frame);
return;
}
const currentDraw = drawRef.current;
prevTime = timestamp;
oldDrawRef.current = currentDraw;
drawRef.current = null;
try {
await currentDraw(timestamp - prevTime);
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
}
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
return () => {
cancelled = true;
};
}, []);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment