From 9cf43442a011ee501a06f520103854fe8c70b586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Thu, 15 Jan 2026 11:25:44 +0800 Subject: [PATCH 1/4] chore: init --- src/useResizeObserver.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/useResizeObserver.ts diff --git a/src/useResizeObserver.ts b/src/useResizeObserver.ts new file mode 100644 index 0000000..01359c0 --- /dev/null +++ b/src/useResizeObserver.ts @@ -0,0 +1,8 @@ +import type { OnResize } from '.'; + +// TODO: Ref observerUtil.ts, realize this. +export default function useResizeObserver( + enabled: boolean, + getTarget: () => HTMLElement, + onResize: OnResize, +) {} From 0e84c436394da8817682b08802c27dc13fefabd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Thu, 15 Jan 2026 12:07:23 +0800 Subject: [PATCH 2/4] chore: refactor --- src/SingleObserver/index.tsx | 93 +++++------------------------------- src/useResizeObserver.ts | 79 ++++++++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 84 deletions(-) diff --git a/src/SingleObserver/index.tsx b/src/SingleObserver/index.tsx index 47d521a..49058d5 100644 --- a/src/SingleObserver/index.tsx +++ b/src/SingleObserver/index.tsx @@ -1,16 +1,16 @@ import { getDOM } from '@rc-component/util/lib/Dom/findDOMNode'; import { supportRef, useComposeRef, getNodeRef } from '@rc-component/util/lib/ref'; import * as React from 'react'; -import type { ResizeObserverProps } from '..'; +import type { ResizeObserverProps, SizeInfo } from '..'; import { CollectionContext } from '../Collection'; -import { observe, unobserve } from '../utils/observerUtil'; +import useResizeObserver from '../useResizeObserver'; export interface SingleObserverProps extends ResizeObserverProps { children: React.ReactElement | ((ref: React.RefObject) => React.ReactElement); } function SingleObserver(props: SingleObserverProps, ref: React.Ref) { - const { children, disabled } = props; + const { children, disabled, onResize, data } = props; const elementRef = React.useRef(null); const onCollectionResize = React.useContext(CollectionContext); @@ -19,14 +19,6 @@ function SingleObserver(props: SingleObserverProps, ref: React.Ref) const isRenderProps = typeof children === 'function'; const mergedChildren = isRenderProps ? children(elementRef) : children; - // ============================= Size ============================= - const sizeRef = React.useRef({ - width: -1, - height: -1, - offsetWidth: -1, - offsetHeight: -1, - }); - // ============================= Ref ============================== const canRef = !isRenderProps && React.isValidElement(mergedChildren) && supportRef(mergedChildren); @@ -35,81 +27,22 @@ function SingleObserver(props: SingleObserverProps, ref: React.Ref) const mergedRef = useComposeRef(originRef, elementRef); const getDomElement = () => { - return getDOM( elementRef.current ) as HTMLElement - } - + return getDOM(elementRef.current) as HTMLElement; + }; React.useImperativeHandle(ref, () => getDomElement()); // =========================== Observe ============================ - const propsRef = React.useRef(props); - propsRef.current = props; - - // Handler - const onInternalResize = React.useCallback((target: HTMLElement) => { - const { onResize, data } = propsRef.current; - - const { width, height } = target.getBoundingClientRect(); - const { offsetWidth, offsetHeight } = target; - - /** - * Resize observer trigger when content size changed. - * In most case we just care about element size, - * let's use `boundary` instead of `contentRect` here to avoid shaking. - */ - const fixedWidth = Math.floor(width); - const fixedHeight = Math.floor(height); - - if ( - sizeRef.current.width !== fixedWidth || - sizeRef.current.height !== fixedHeight || - sizeRef.current.offsetWidth !== offsetWidth || - sizeRef.current.offsetHeight !== offsetHeight - ) { - const size = { width: fixedWidth, height: fixedHeight, offsetWidth, offsetHeight }; - sizeRef.current = size; - - // IE is strange, right? - const mergedOffsetWidth = offsetWidth === Math.round(width) ? width : offsetWidth; - const mergedOffsetHeight = offsetHeight === Math.round(height) ? height : offsetHeight; - - const sizeInfo = { - ...size, - offsetWidth: mergedOffsetWidth, - offsetHeight: mergedOffsetHeight, - }; - - // Let collection know what happened - onCollectionResize?.(sizeInfo, target, data); - - if (onResize) { - // defer the callback but not defer to next frame - Promise.resolve().then(() => { - onResize(sizeInfo, target); - }); - } - } - }, []); - - // Dynamic observe - React.useEffect(() => { - const currentElement: HTMLElement = getDomElement(); - - if (currentElement && !disabled) { - observe(currentElement, onInternalResize); - } - - return () => unobserve(currentElement, onInternalResize); - }, [elementRef.current, disabled]); + useResizeObserver(!disabled, getDomElement, onResize, (sizeInfo, target) => { + onCollectionResize?.(sizeInfo, target, data); + }); // ============================ Render ============================ - return ( - canRef - ? React.cloneElement(mergedChildren as any, { - ref: mergedRef, - }) - : mergedChildren - ); + return canRef + ? React.cloneElement(mergedChildren as any, { + ref: mergedRef, + }) + : mergedChildren; } const RefSingleObserver = React.forwardRef(SingleObserver); diff --git a/src/useResizeObserver.ts b/src/useResizeObserver.ts index 01359c0..f8aedf6 100644 --- a/src/useResizeObserver.ts +++ b/src/useResizeObserver.ts @@ -1,8 +1,79 @@ -import type { OnResize } from '.'; +import * as React from 'react'; +import type { OnResize, SizeInfo } from '.'; +import { observe, unobserve } from './utils/observerUtil'; +import { useEvent } from '@rc-component/util'; -// TODO: Ref observerUtil.ts, realize this. export default function useResizeObserver( enabled: boolean, getTarget: () => HTMLElement, - onResize: OnResize, -) {} + onDelayResize?: OnResize, + onSyncResize?: OnResize, +) { + // ============================= Size ============================= + const sizeRef = React.useRef({ + width: -1, + height: -1, + offsetWidth: -1, + offsetHeight: -1, + }); + + // =========================== Observe ============================ + + // Handler + const onInternalResize = useEvent((target: HTMLElement) => { + const { width, height } = target.getBoundingClientRect(); + const { offsetWidth, offsetHeight } = target; + + /** + * Resize observer trigger when content size changed. + * In most case we just care about element size, + * let's use `boundary` instead of `contentRect` here to avoid shaking. + */ + const fixedWidth = Math.floor(width); + const fixedHeight = Math.floor(height); + + if ( + sizeRef.current.width !== fixedWidth || + sizeRef.current.height !== fixedHeight || + sizeRef.current.offsetWidth !== offsetWidth || + sizeRef.current.offsetHeight !== offsetHeight + ) { + const size = { width: fixedWidth, height: fixedHeight, offsetWidth, offsetHeight }; + sizeRef.current = size; + + // IE is strange, right? + const mergedOffsetWidth = offsetWidth === Math.round(width) ? width : offsetWidth; + const mergedOffsetHeight = offsetHeight === Math.round(height) ? height : offsetHeight; + + const sizeInfo = { + ...size, + offsetWidth: mergedOffsetWidth, + offsetHeight: mergedOffsetHeight, + }; + + // Call the callback immediately, let the caller decide whether to defer + // onResize(sizeInfo, target); + onSyncResize?.(sizeInfo, target); + + // defer the callback but not defer to next frame + Promise.resolve().then(() => { + onDelayResize?.(sizeInfo, target); + }); + } + }); + + // Dynamic observe + React.useEffect(() => { + const target = getTarget(); + + if (target && enabled) { + observe(target, onInternalResize); + } + + return () => { + if (target) { + unobserve(target, onInternalResize); + } + }; + }, [enabled, getTarget]); +} From 1614b4a18b937c69c916aa05d4bd834605e7d6a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Thu, 15 Jan 2026 14:36:06 +0800 Subject: [PATCH 3/4] chore: export --- src/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.tsx b/src/index.tsx index ee252ca..eac0df1 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -12,6 +12,8 @@ export { _rs, }; +export { default as useResizeObserver } from './useResizeObserver'; + export interface SizeInfo { width: number; height: number; From 479bc86d1dcc574bc9b867489816e1be24228317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Thu, 15 Jan 2026 14:45:30 +0800 Subject: [PATCH 4/4] chore: fix lint --- package.json | 11 ++++++----- src/SingleObserver/index.tsx | 2 +- src/useResizeObserver.ts | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index c0aa975..cfe01d8 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "@types/node": "^24.5.2", "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", - "@umijs/fabric": "^2.0.9", + "@umijs/fabric": "^4.0.0", "cheerio": "1.0.0-rc.12", "coveralls": "^3.0.6", "cross-env": "^7.0.2", @@ -68,19 +68,20 @@ "rc-test": "^7.0.15", "react": "^16.0.0", "react-dom": "^16.0.0", - "regenerator-runtime": "^0.14.0" + "regenerator-runtime": "^0.14.0", + "eslint": "8.x" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" }, "resolutions": { - "@types/minimatch": "5.1.2" - }, + "@types/minimatch": "5.1.2" + }, "cnpm": { "mode": "npm" }, "tnpm": { "mode": "npm" } -} +} \ No newline at end of file diff --git a/src/SingleObserver/index.tsx b/src/SingleObserver/index.tsx index 49058d5..c05bf86 100644 --- a/src/SingleObserver/index.tsx +++ b/src/SingleObserver/index.tsx @@ -1,7 +1,7 @@ import { getDOM } from '@rc-component/util/lib/Dom/findDOMNode'; import { supportRef, useComposeRef, getNodeRef } from '@rc-component/util/lib/ref'; import * as React from 'react'; -import type { ResizeObserverProps, SizeInfo } from '..'; +import type { ResizeObserverProps } from '..'; import { CollectionContext } from '../Collection'; import useResizeObserver from '../useResizeObserver'; diff --git a/src/useResizeObserver.ts b/src/useResizeObserver.ts index f8aedf6..2fe4810 100644 --- a/src/useResizeObserver.ts +++ b/src/useResizeObserver.ts @@ -75,5 +75,5 @@ export default function useResizeObserver( unobserve(target, onInternalResize); } }; - }, [enabled, getTarget]); + }, [enabled]); }