UNPKG

1.93 kBJavaScriptView Raw
1import useCustomEffect from './useCustomEffect';
2import { dequal } from 'dequal';
3import useImmediateUpdateEffect from './useImmediateUpdateEffect';
4import useEventCallback from './useEventCallback';
5import { useState } from 'react';
6
7function isDepsEqual(_ref, _ref2) {
8 var nextElement = _ref[0],
9 nextConfig = _ref[1];
10 var prevElement = _ref2[0],
11 prevConfig = _ref2[1];
12 return nextElement === prevElement && dequal(nextConfig, prevConfig);
13}
14/**
15 * Observe mutations on a DOM node or tree of DOM nodes.
16 * Depends on the `MutationObserver` api.
17 *
18 * ```tsx
19 * const [element, attachRef] = useCallbackRef(null);
20 *
21 * useMutationObserver(element, { subtree: true }, (records) => {
22 *
23 * });
24 *
25 * return (
26 * <div ref={attachRef} />
27 * )
28 * ```
29 *
30 * @param element The DOM element to observe
31 * @param config The observer configuration
32 * @param callback A callback fired when a mutation occurs
33 */
34
35
36function useMutationObserver(element, config, callback) {
37 var _useState = useState(null),
38 records = _useState[0],
39 setRecords = _useState[1];
40
41 var handler = useEventCallback(callback || setRecords);
42 useCustomEffect(function () {
43 if (!element) return; // The behavior around reusing mutation observers is confusing
44 // observing again _should_ disable the last listener but doesn't
45 // seem to always be the case, maybe just in JSDOM? In any case the cost
46 // to redeclaring it is gonna be fairly low anyway, so make it simple
47
48 var observer = new MutationObserver(handler);
49 observer.observe(element, config);
50 return function () {
51 observer.disconnect();
52 };
53 }, [element, config], {
54 isEqual: isDepsEqual,
55 // Intentionally done in render, otherwise observer will miss any
56 // changes made to the DOM during this update
57 effectHook: useImmediateUpdateEffect
58 });
59 return callback ? void 0 : records || [];
60}
61
62export default useMutationObserver;
\No newline at end of file