Skip to content

[BUG] useResizeObserver when component dom remove and rerender ( like dialog ), size not update #632

@hxdyj

Description

@hxdyj

Describe the bug

useResizeObserver when component dom remove and rerender ( like dialog ), size not refresh

To Reproduce

windows chrome

Expected behavior

when useResizeObserver ref dom remove and while readd to document need update size.
or export creatResizeObserver and destroyResizeObserver function give to developer to control.
like below:

function useResizeObserver(options) {
	const { ref, box = "content-box" } = options;
	const [{ width, height }, setSize] = useState(initialSize);
	const isMounted = useIsMounted();
	const previousSize = useRef({ ...initialSize });
	const onResize = useRef(void 0);
	onResize.current = options.onResize;
	const observerRef = useRef(null)
	const createResizeObserver = useCallback(() => {
		if (!ref.current)
			return;
		if (typeof window === "undefined" || !("ResizeObserver" in window))
			return;
		observerRef.current = new ResizeObserver(([entry]) => {
			const boxProp = box === "border-box" ? "borderBoxSize" : box === "device-pixel-content-box" ? "devicePixelContentBoxSize" : "contentBoxSize";
			const newWidth = extractSize(entry, boxProp, "inlineSize");
			const newHeight = extractSize(entry, boxProp, "blockSize");
			const hasChanged = previousSize.current.width !== newWidth || previousSize.current.height !== newHeight;
			if (hasChanged) {
				const newSize = { width: newWidth, height: newHeight };
				previousSize.current.width = newWidth;
				previousSize.current.height = newHeight;
				if (onResize.current) {
					onResize.current(newSize);
				} else {
					if (isMounted()) {
						setSize(newSize);
					}
				}
			}
		});
		observerRef.current.observe(ref.current, { box });
	}, [isMounted, observerRef, box, ref])

	const destroyResizeObserver = useCallback(() => {
		if (observerRef.current) {
			observerRef.current.disconnect();
			previousSize.current = initialSize;
			observerRef.current = null;
		}
	}, [observerRef])

	useEffect(() => {
		createResizeObserver()
		return () => {
			destroyResizeObserver()
		}
	}, [box, ref, isMounted]);

	return { width, height, createResizeObserver, destroyResizeObserver };  // Notice: here add  createResizeObserver, destroyResizeObserver 
}

Additional context

No response

Activity

changed the title [-][BUG] useResizeObserver when component dom remove and rerender ( like dialog ), size not refresh[/-] [+][BUG] useResizeObserver when component dom remove and rerender ( like dialog ), size not update[/+] on Aug 20, 2024
farzadsoltani

farzadsoltani commented on Oct 24, 2024

@farzadsoltani

Did you figure out a fix for this?

hxdyj

hxdyj commented on Oct 24, 2024

@hxdyj
Author

@farzadsoltani I am patch package by below diff, add destroyResizeObserver function to control.

diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000000000000000000000000000000000..00c86b5d74a94f2de43efd2ca25111e3d79fd205
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+	"editor.formatOnSave": false
+}
diff --git a/dist/index.d.ts b/dist/index.d.ts
index 3d80dda3a48539d9dac356a1fe8b212f7e75ac56..a9ed7d296f8b9a51a2edcf339c0ec9c05f44ad62 100644
--- a/dist/index.d.ts
+++ b/dist/index.d.ts
@@ -665,7 +665,10 @@ type UseResizeObserverOptions<T extends HTMLElement = HTMLElement> = {
  * <div ref={myRef}>Hello, world!</div>
  * ```
  */
-declare function useResizeObserver<T extends HTMLElement = HTMLElement>(options: UseResizeObserverOptions<T>): Size;
+declare function useResizeObserver<T extends HTMLElement = HTMLElement>(options: UseResizeObserverOptions<T>): Size&{
+    createResizeObserver: () => void
+	destroyResizeObserver: () => void
+};
 
 /**
  * The hooks options.
diff --git a/dist/index.js b/dist/index.js
index dc0b5e680c83fcc8b9bf51c35e9de2ba500fa6fa..7b9358584f35e6d3aba40b78bfc72a3022ce10b2 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -605,41 +605,55 @@ var initialSize = {
   height: void 0
 };
 function useResizeObserver(options) {
-  const { ref, box = "content-box" } = options;
-  const [{ width, height }, setSize] = useState(initialSize);
-  const isMounted = useIsMounted();
-  const previousSize = useRef({ ...initialSize });
-  const onResize = useRef(void 0);
-  onResize.current = options.onResize;
-  useEffect(() => {
-    if (!ref.current)
-      return;
-    if (typeof window === "undefined" || !("ResizeObserver" in window))
-      return;
-    const observer = new ResizeObserver(([entry]) => {
-      const boxProp = box === "border-box" ? "borderBoxSize" : box === "device-pixel-content-box" ? "devicePixelContentBoxSize" : "contentBoxSize";
-      const newWidth = extractSize(entry, boxProp, "inlineSize");
-      const newHeight = extractSize(entry, boxProp, "blockSize");
-      const hasChanged = previousSize.current.width !== newWidth || previousSize.current.height !== newHeight;
-      if (hasChanged) {
-        const newSize = { width: newWidth, height: newHeight };
-        previousSize.current.width = newWidth;
-        previousSize.current.height = newHeight;
-        if (onResize.current) {
-          onResize.current(newSize);
-        } else {
-          if (isMounted()) {
-            setSize(newSize);
-          }
-        }
-      }
-    });
-    observer.observe(ref.current, { box });
-    return () => {
-      observer.disconnect();
-    };
-  }, [box, ref, isMounted]);
-  return { width, height };
+	const { ref, box = "content-box" } = options;
+	const [{ width, height }, setSize] = useState(initialSize);
+	const isMounted = useIsMounted();
+	const previousSize = useRef({ ...initialSize });
+	const onResize = useRef(void 0);
+	onResize.current = options.onResize;
+	const observerRef = useRef(null)
+	const createResizeObserver = useCallback(() => {
+		if (!ref.current)
+			return;
+		if (typeof window === "undefined" || !("ResizeObserver" in window))
+			return;
+		observerRef.current = new ResizeObserver(([entry]) => {
+			const boxProp = box === "border-box" ? "borderBoxSize" : box === "device-pixel-content-box" ? "devicePixelContentBoxSize" : "contentBoxSize";
+			const newWidth = extractSize(entry, boxProp, "inlineSize");
+			const newHeight = extractSize(entry, boxProp, "blockSize");
+			const hasChanged = previousSize.current.width !== newWidth || previousSize.current.height !== newHeight;
+			if (hasChanged) {
+				const newSize = { width: newWidth, height: newHeight };
+				previousSize.current.width = newWidth;
+				previousSize.current.height = newHeight;
+				if (onResize.current) {
+					onResize.current(newSize);
+				} else {
+					if (isMounted()) {
+						setSize(newSize);
+					}
+				}
+			}
+		});
+		observerRef.current.observe(ref.current, { box });
+	}, [isMounted, observerRef, box, ref])
+
+	const destroyResizeObserver = useCallback(() => {
+		if (observerRef.current) {
+			observerRef.current.disconnect();
+			previousSize.current = initialSize;
+			observerRef.current = null;
+		}
+	}, [observerRef])
+
+	useEffect(() => {
+		createResizeObserver()
+		return () => {
+			destroyResizeObserver()
+		}
+	}, [box, ref, isMounted]);
+
+	return { width, height, createResizeObserver, destroyResizeObserver };
 }
 function extractSize(entry, box, sizeType) {
   if (!entry[box]) {
thejasonxie

thejasonxie commented on Dec 3, 2024

@thejasonxie

Easiest solution I found :

modify this line by using ref?.current.

it starts working after user clicks on the dialog which is okay in my case. I'm using shadcn dialog.

addlistener

addlistener commented on Mar 4, 2025

@addlistener

I'm using this
https://ahooks.js.org/hooks/use-size/

---The below is still buggy---

or more easily, without patching the original package, create a ref object manually.

const { height: topSectionHeight } = useResizeObserver({
    ref: {
      current: topSectionRef.current,
    },
    box: "border-box",
  });
linked a pull request that will close this issue on Apr 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @addlistener@hxdyj@thejasonxie@farzadsoltani

      Issue actions

        [BUG] useResizeObserver when component dom remove and rerender ( like dialog ), size not update · Issue #632 · juliencrn/usehooks-ts