Skip to content

Commit 322b9f9

Browse files
authored
refactor: get hooks (#7)
* chore: move * chore: fix export * chore: refactor * chore: update effect deps
1 parent 1082b46 commit 322b9f9

3 files changed

Lines changed: 94 additions & 68 deletions

File tree

src/MutateObserver.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React from 'react';
2+
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
3+
import { supportRef, useComposeRef } from 'rc-util/lib/ref';
4+
import findDOMNode from 'rc-util/lib/Dom/findDOMNode';
5+
import useEvent from 'rc-util/lib/hooks/useEvent';
6+
import DomWrapper from './wrapper';
7+
import type { MutationObserverProps } from './interface';
8+
import useMutateObserver from './useMutateObserver';
9+
10+
const MutateObserver: React.FC<MutationObserverProps> = props => {
11+
const { children, options, onMutate = () => {} } = props;
12+
13+
const callback = useEvent(onMutate);
14+
15+
const wrapperRef = React.useRef<DomWrapper>(null);
16+
17+
const elementRef = React.useRef<HTMLElement>(null);
18+
19+
const canRef = React.isValidElement(children) && supportRef(children);
20+
21+
const mergedRef = useComposeRef(
22+
elementRef,
23+
canRef ? (children as any).ref : null,
24+
);
25+
26+
const [target, setTarget] = React.useState<HTMLElement>(null);
27+
28+
useMutateObserver(target, callback, options);
29+
30+
// =========================== Effect ===========================
31+
// Bind target
32+
useLayoutEffect(() => {
33+
setTarget(
34+
findDOMNode(elementRef.current) || findDOMNode(wrapperRef.current),
35+
);
36+
});
37+
38+
// =========================== Render ===========================
39+
if (!children) {
40+
if (process.env.NODE_ENV !== 'production') {
41+
console.error('MutationObserver need children props');
42+
}
43+
return null;
44+
}
45+
46+
return (
47+
<DomWrapper ref={wrapperRef}>
48+
{canRef
49+
? React.cloneElement(children as any, { ref: mergedRef })
50+
: children}
51+
</DomWrapper>
52+
);
53+
};
54+
55+
export default MutateObserver;

src/index.tsx

Lines changed: 3 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,6 @@
1-
import React, { useEffect, useRef } from 'react';
2-
import { composeRef, supportRef } from 'rc-util/lib/ref';
3-
import findDOMNode from 'rc-util/lib/Dom/findDOMNode';
4-
import canUseDom from 'rc-util/lib/Dom/canUseDom';
5-
import useEvent from 'rc-util/lib/hooks/useEvent';
6-
import DomWrapper from './wrapper';
7-
import type { MutationObserverProps } from './interface';
1+
import MutateObserver from './MutateObserver';
2+
import useMutateObserver from './useMutateObserver';
83

9-
const defOptions: MutationObserverInit = {
10-
subtree: true,
11-
childList: true,
12-
attributeFilter: ['style', 'class'],
13-
};
14-
15-
const MutateObserver: React.FC<MutationObserverProps> = props => {
16-
const { children, options = defOptions, onMutate = () => {} } = props;
17-
18-
const callback = useEvent(onMutate);
19-
20-
const wrapperRef = useRef<DomWrapper>(null);
21-
22-
const elementRef = React.useRef<HTMLElement>(null);
23-
24-
const canRef = React.isValidElement(children) && supportRef(children);
25-
26-
const originRef: React.Ref<Element> = canRef ? (children as any)?.ref : null;
27-
28-
const mergedRef = React.useMemo<React.Ref<Element>>(
29-
() => composeRef<Element>(originRef, elementRef),
30-
[originRef, elementRef],
31-
);
32-
33-
useEffect(() => {
34-
if (!canUseDom()) {
35-
return;
36-
}
37-
38-
let instance: MutationObserver;
39-
40-
const currentElement =
41-
findDOMNode((originRef as any)?.current) ||
42-
findDOMNode(wrapperRef?.current);
43-
44-
if (currentElement && 'MutationObserver' in window) {
45-
instance = new MutationObserver(callback);
46-
instance.observe(currentElement, options);
47-
}
48-
return () => {
49-
instance?.takeRecords();
50-
instance?.disconnect();
51-
};
52-
// eslint-disable-next-line react-hooks/exhaustive-deps
53-
}, [options, originRef]);
54-
55-
if (!children) {
56-
if (process.env.NODE_ENV !== 'production') {
57-
console.error('MutationObserver need children props');
58-
}
59-
return null;
60-
}
61-
62-
return (
63-
<DomWrapper ref={wrapperRef}>
64-
{canRef
65-
? React.cloneElement(children as any, { ref: mergedRef })
66-
: children}
67-
</DomWrapper>
68-
);
69-
};
4+
export { useMutateObserver };
705

716
export default MutateObserver;

src/useMutateObserver.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import canUseDom from 'rc-util/lib/Dom/canUseDom';
2+
import * as React from 'react';
3+
4+
const defaultOptions: MutationObserverInit = {
5+
subtree: true,
6+
childList: true,
7+
attributeFilter: ['style', 'class'],
8+
};
9+
10+
export default function useMutateObserver(
11+
nodeOrList: HTMLElement | HTMLElement[],
12+
callback: MutationCallback,
13+
options: MutationObserverInit = defaultOptions,
14+
) {
15+
React.useEffect(() => {
16+
if (!canUseDom() || !nodeOrList) {
17+
return;
18+
}
19+
20+
let instance: MutationObserver;
21+
22+
const nodeList = Array.isArray(nodeOrList) ? nodeOrList : [nodeOrList];
23+
24+
if ('MutationObserver' in window) {
25+
instance = new MutationObserver(callback);
26+
27+
nodeList.forEach(element => {
28+
instance.observe(element, options);
29+
});
30+
}
31+
return () => {
32+
instance?.takeRecords();
33+
instance?.disconnect();
34+
};
35+
}, [options, nodeOrList]);
36+
}

0 commit comments

Comments
 (0)