-
Notifications
You must be signed in to change notification settings - Fork 246
Expand file tree
/
Copy pathuseSafeRefCallback.ts
More file actions
44 lines (40 loc) · 1.36 KB
/
useSafeRefCallback.ts
File metadata and controls
44 lines (40 loc) · 1.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import { useMemo } from 'react';
type SafeCallbackRef<T> = (node: T) => (() => void) | void;
/**
* useSafeRefCallback will call a cleanup function (returned from the passed callback)
* whenever the component is re-rendered ( similar to useEffect, but in a callbackRef )
*
* Caveat: Usually, callback refs are called with `null` when the component is unmounted. The returned callback from this hook will only be called whenever `node !== null`.
* For cases where you want to do some action when the node is null, you should rely on the cleanup function to be called.
*
* @example
* const callback = useSafeRefCallback(
* useCallback(
* // node will always exist
* (node: HTMLDivElement) => {
* node.addEventListener('click', listener);
* return () => {
* node.removeEventListener('click', listener);
* };
* },
* [listener],
* ),
* );
*
*/
export const useSafeRefCallback = <T extends HTMLElement>(
callback: SafeCallbackRef<T>,
) =>
useMemo(() => {
let cleanup: (() => void) | null = null;
return (node: T | null): void => {
if (node === null) {
if (typeof cleanup === 'function') {
cleanup();
cleanup = null;
}
return;
}
cleanup = callback(node) || null;
};
}, [callback]);