1- import useEffect from './useIsomorphicEffect'
1+ import useCustomEffect , { IsEqual } from './useCustomEffect'
2+ import isEqual from 'lodash/isEqual'
3+ import useImmediateUpdateEffect from './useImmediateUpdateEffect'
4+ import useMountEffect from './useMountEffect'
5+ import useEventCallback from './useEventCallback'
6+ import { useRef } from 'react'
7+
8+ type Deps = [ Element | null | undefined , MutationObserverInit ]
9+
10+ const isDepsEqual : IsEqual < Deps > = ( prev , next ) =>
11+ prev [ 0 ] === next [ 0 ] && isEqual ( prev [ 1 ] , next [ 1 ] )
212
313/**
4- * Efficiently observe size changes on an element. Depends on the `ResizeObserver` api,
5- * and polyfills are needed in older browsers .
14+ * Observe mutations on a DOM node or tree of DOM nodes.
15+ * Depends on the `MutationObserver` api .
616 *
717 * ```ts
818 * const [element, attachRef] = useCallbackRef(null);
@@ -25,45 +35,34 @@ function useMutationObserver(
2535 config : MutationObserverInit ,
2636 callback : MutationCallback ,
2737) : void {
28- const {
29- attributeFilter,
30- attributeOldValue,
31- attributes,
32- characterData,
33- characterDataOldValue,
34- childList,
35- subtree,
36- } = config
38+ const observerRef = useRef < MutationObserver | null > ( )
39+ const fn = useEventCallback ( callback )
3740
38- useEffect ( ( ) => {
41+ useMountEffect ( ( ) => {
3942 if ( ! element ) return
4043
41- const observer = new MutationObserver ( callback )
44+ observerRef . current = new MutationObserver ( fn )
45+ } )
46+
47+ useCustomEffect (
48+ ( ) => {
49+ if ( ! element ) return
4250
43- observer . observe ( element , {
44- attributeFilter,
45- attributeOldValue,
46- attributes,
47- characterData,
48- characterDataOldValue,
49- childList,
50- subtree,
51- } )
51+ const observer = observerRef . current || new MutationObserver ( fn )
52+ observer . observe ( element , config )
5253
53- return ( ) => {
54- observer . disconnect ( )
55- }
56- } , [
57- element ,
58- callback ,
59- attributeFilter ?. join ( ',' ) ,
60- attributeOldValue ,
61- attributes ,
62- characterData ,
63- characterDataOldValue ,
64- childList ,
65- subtree ,
66- ] )
54+ return ( ) => {
55+ observer . disconnect ( )
56+ }
57+ } ,
58+ [ element , config ] ,
59+ {
60+ isEqual : isDepsEqual ,
61+ // Intentionally done in render, otherwise observer will miss any
62+ // changes made to the DOM during this update
63+ effectHook : useImmediateUpdateEffect ,
64+ } ,
65+ )
6766}
6867
6968export default useMutationObserver
0 commit comments