From c4c2ba819df0830337ed68d899b72abbec790c62 Mon Sep 17 00:00:00 2001 From: Moritz Heckmann <77104411+dvmoritzschoefl@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:01:11 +0100 Subject: [PATCH] Added useTriggerFrame hook (#624) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added useTriggerFrame hook * Used useSyncedRef * changed to useEvent for useTriggerFrame * changed to useEvent for useTriggerFrame --------- Co-authored-by: Michael PĆ¼hringer <51900829+puehringer@users.noreply.github.com> --- src/vis/vishooks/hooks/index.ts | 1 + src/vis/vishooks/hooks/useTriggerFrame.ts | 51 +++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/vis/vishooks/hooks/useTriggerFrame.ts diff --git a/src/vis/vishooks/hooks/index.ts b/src/vis/vishooks/hooks/index.ts index 601c8afa5..9327e31e4 100644 --- a/src/vis/vishooks/hooks/index.ts +++ b/src/vis/vishooks/hooks/index.ts @@ -9,3 +9,4 @@ export * from './useBrush'; export * from './useLasso'; export * from './useLinearScale'; export * from './useCanvas'; +export * from './useTriggerFrame'; diff --git a/src/vis/vishooks/hooks/useTriggerFrame.ts b/src/vis/vishooks/hooks/useTriggerFrame.ts new file mode 100644 index 000000000..17a721c41 --- /dev/null +++ b/src/vis/vishooks/hooks/useTriggerFrame.ts @@ -0,0 +1,51 @@ +/* eslint-disable react-compiler/react-compiler */ +import * as React from 'react'; + +import isEqual from 'lodash/isEqual'; +import { useEvent } from '../../../hooks'; + +/** + * Hook similar to useEffect that triggers a frame when dependencies change. + * It will deeply compare the dependencies and only trigger a frame if they have changed. + * Frames are debounced to the next animation frame to ensure consistency with the + * display refresh rate. The optional profileId gives insights on the frame timings. + * + * Usage: + * + * ```tsx + * useTriggerFrame(() => { + * // Your frame code here + * }, [dependencies]); + * ``` + */ +export function useTriggerFrame(frame: () => void, deps: React.DependencyList, profileId?: string) { + const frameRef = React.useRef(undefined); + const depsRef = React.useRef(deps); + + const callbackEvent = useEvent(frame); + + if (!isEqual(depsRef.current, deps)) { + depsRef.current = deps; + + // Request new frame + if (frameRef.current === undefined) { + frameRef.current = requestAnimationFrame(() => { + frameRef.current = undefined; + + if (profileId) { + let msg = ''; + const t0 = performance.now(); + msg += `Profile: ${profileId}`; + + callbackEvent(); + + const t1 = performance.now(); + msg += ` took ${t1 - t0} milliseconds.`; + console.log(msg); + } else { + callbackEvent(); + } + }); + } + } +}