diff --git a/src/MutateObserver.tsx b/src/MutateObserver.tsx index 68b5d48..9f28d13 100644 --- a/src/MutateObserver.tsx +++ b/src/MutateObserver.tsx @@ -1,9 +1,12 @@ -import React from 'react'; -import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect'; -import { supportRef, useComposeRef } from '@rc-component/util/lib/ref'; -import findDOMNode from '@rc-component/util/lib/Dom/findDOMNode'; +import { getDOM } from '@rc-component/util/lib/Dom/findDOMNode'; import useEvent from '@rc-component/util/lib/hooks/useEvent'; -import DomWrapper from './wrapper'; +import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect'; +import { + getNodeRef, + supportNodeRef, + useComposeRef, +} from '@rc-component/util/lib/ref'; +import React from 'react'; import type { MutationObserverProps } from './interface'; import useMutateObserver from './useMutateObserver'; @@ -12,28 +15,23 @@ const MutateObserver: React.FC = props => { const callback = useEvent(onMutate); - const wrapperRef = React.useRef(null); - - const elementRef = React.useRef(null); + const elementRef = React.useRef(null); - const canRef = React.isValidElement(children) && supportRef(children); + const canRef = supportNodeRef(children); - const mergedRef = useComposeRef( - elementRef, - canRef ? (children as any).ref : null, - ); + const mergedRef = useComposeRef(elementRef, getNodeRef(children)); - const [target, setTarget] = React.useState(null); + const [target, setTarget] = React.useState(null); useMutateObserver(target, callback, options); // =========================== Effect =========================== - // Bind target useLayoutEffect(() => { - setTarget( - findDOMNode(elementRef.current) || findDOMNode(wrapperRef.current), - ); - }); + // Set target based on the refs + if (canRef && elementRef.current) { + setTarget(getDOM(elementRef.current)); + } + }, [canRef]); // =========================== Render =========================== if (!children) { @@ -43,13 +41,9 @@ const MutateObserver: React.FC = props => { return null; } - return ( - - {canRef - ? React.cloneElement(children, { ref: mergedRef }) - : children} - - ); + return canRef + ? React.cloneElement(children, { ref: mergedRef }) + : children; }; export default MutateObserver; diff --git a/src/useMutateObserver.tsx b/src/useMutateObserver.tsx index f0edd28..2f30968 100644 --- a/src/useMutateObserver.tsx +++ b/src/useMutateObserver.tsx @@ -8,7 +8,7 @@ const defaultOptions: MutationObserverInit = { }; const useMutateObserver = ( - nodeOrList: HTMLElement | HTMLElement[], + nodeOrList: HTMLElement | HTMLElement[] | SVGElement | SVGElement[], callback: MutationCallback, options: MutationObserverInit = defaultOptions, ) => { diff --git a/src/wrapper.ts b/src/wrapper.ts deleted file mode 100644 index 3b0e4ab..0000000 --- a/src/wrapper.ts +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; - -class DomWrapper extends React.Component { - render() { - return this.props.children; - } -} - -export default DomWrapper; diff --git a/tests/index.test.tsx b/tests/index.test.tsx index c9afeb2..ffd48aa 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -1,8 +1,20 @@ -import React from 'react'; import { fireEvent, render } from '@testing-library/react'; +import React from 'react'; import MutateObserver from '../src'; +jest.mock('../src/useMutateObserver', () => { + const origin = jest.requireActual('../src/useMutateObserver').default; + return (...args) => { + global.mutateTargetElement = args[0]; + return origin(...args); + }; +}); + describe('MutateObserver', () => { + beforeEach(() => { + global.mutateTargetElement = null; + }); + it('MutateObserver should support onMutate', () => { const fn = jest.fn(); const Demo: React.FC = () => { @@ -19,7 +31,11 @@ describe('MutateObserver', () => { ); }; const { container, unmount } = render(); + + // Simulate a click event fireEvent.click(container.querySelector('button')!); + + // Check if the callback was triggered if ('MutationObserver' in window) { expect(fn).toHaveBeenCalled(); } else { @@ -28,10 +44,13 @@ describe('MutateObserver', () => { unmount(); }); - it('findDOMNode should not error in React.StrictMode', () => { + it('MutateObserver should work without errors in React.StrictMode', () => { const fn = jest.fn(); const buttonRef = React.createRef(); + + // Mock console.error to ensure no warnings are logged const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + const Demo = React.forwardRef< HTMLButtonElement, React.HTMLAttributes @@ -52,9 +71,41 @@ describe('MutateObserver', () => { ); }); + const { container } = render(); + + // Simulate a click event fireEvent.click(container.querySelector('button')!); + + // Ensure no warnings were logged expect(warnSpy).not.toHaveBeenCalled(); + + // Restore original console.error warnSpy.mockRestore(); }); + + it('should support nativeElement', () => { + const Demo = React.forwardRef< + { + nativeElement: HTMLElement; + }, + object + >((props, ref) => { + const eleRef = React.useRef(null); + React.useImperativeHandle(ref, () => ({ + nativeElement: eleRef.current, + })); + return
; + }); + + const onMutate = jest.fn(); + + const { container } = render( + + + , + ); + + expect(global.mutateTargetElement).toBe(container.querySelector('.bamboo')); + }); });