Skip to content

Instantly share code, notes, and snippets.

@gvergnaud
Last active August 9, 2023 19:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gvergnaud/0c83ade9ae3a75c6e8191c57614d9b13 to your computer and use it in GitHub Desktop.
Save gvergnaud/0c83ade9ae3a75c6e8191c57614d9b13 to your computer and use it in GitHub Desktop.
raf-throttle.ts
type RafState<Args> =
| { type: 'waiting'; latestArgs: Args; rafId: number }
| { type: 'idle' };
export const animationFrameThrottle = <Args extends any[]>(
callback: (...args: Args) => unknown,
): ((...args: Args) => void) & { cancel: () => void } => {
let state: RafState<Args> = { type: 'idle' };
const cancel = () => {
if (state.type === 'waiting') {
window.cancelAnimationFrame(state.rafId);
state = { type: 'idle' };
}
};
const onRaf = () => {
if (state.type === 'waiting') {
callback(...state.latestArgs);
state = { type: 'idle' };
}
};
const call = (...args: Args) => {
switch (state.type) {
case 'waiting': {
state.latestArgs = args;
break;
}
case 'idle': {
state = {
type: 'waiting',
latestArgs: args,
rafId: window.requestAnimationFrame(onRaf),
};
break;
}
}
};
return Object.assign(call, { cancel });
};
import React from 'react';
import { animationFrameThrottle } from './raf-throttle';
const Component = () => {
const onMouseMove = React.useMemo(() =>
animationFrameThrottle(() => setState('move')),
);
return (
<div
onMouseMove={onMouseMove}
onMouseLeave={(e) => {
onMouseMove.cancel();
setState('leave');
}}
/>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment