Last active
October 5, 2020 09:30
-
-
Save flamerohr/d70433e8c910d14463631e5fc36ff83f to your computer and use it in GitHub Desktop.
An animation frame hook
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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