UNPKG

2.2 kBJavaScriptView Raw
1import { useRef } from 'react';
2import useMounted from './useMounted';
3import useEventCallback from './useEventCallback';
4const isSyntheticEvent = event => typeof event.persist === 'function';
5/**
6 * Creates a event handler function throttled by `requestAnimationFrame` that
7 * returns the **most recent** event. Useful for noisy events that update react state.
8 *
9 * ```tsx
10 * function Component() {
11 * const [position, setPosition] = useState();
12 * const handleMove = useThrottledEventHandler<React.PointerEvent>(
13 * (event) => {
14 * setPosition({
15 * top: event.clientX,
16 * left: event.clientY,
17 * })
18 * }
19 * )
20 *
21 * return (
22 * <div onPointerMove={handleMove}>
23 * <div style={position} />
24 * </div>
25 * );
26 * }
27 * ```
28 *
29 * @param handler An event handler function
30 * @typeParam TEvent The event object passed to the handler function
31 * @returns The event handler with a `clear` method attached for clearing any in-flight handler calls
32 *
33 */
34export default function useThrottledEventHandler(handler) {
35 const isMounted = useMounted();
36 const eventHandler = useEventCallback(handler);
37 const nextEventInfoRef = useRef({
38 event: null,
39 handle: null
40 });
41 const clear = () => {
42 cancelAnimationFrame(nextEventInfoRef.current.handle);
43 nextEventInfoRef.current.handle = null;
44 };
45 const handlePointerMoveAnimation = () => {
46 const {
47 current: next
48 } = nextEventInfoRef;
49 if (next.handle && next.event) {
50 if (isMounted()) {
51 next.handle = null;
52 eventHandler(next.event);
53 }
54 }
55 next.event = null;
56 };
57 const throttledHandler = event => {
58 if (!isMounted()) return;
59 if (isSyntheticEvent(event)) {
60 event.persist();
61 }
62 // Special handling for a React.Konva event which reuses the
63 // event object as it bubbles, setting target
64 else if ('evt' in event) {
65 event = Object.assign({}, event);
66 }
67 nextEventInfoRef.current.event = event;
68 if (!nextEventInfoRef.current.handle) {
69 nextEventInfoRef.current.handle = requestAnimationFrame(handlePointerMoveAnimation);
70 }
71 };
72 throttledHandler.clear = clear;
73 return throttledHandler;
74}
\No newline at end of file