From ff35d843b6739a04c21772cfcbe6e405fc45bf27 Mon Sep 17 00:00:00 2001 From: David Matejka Date: Fri, 27 Oct 2023 16:00:42 +0200 Subject: [PATCH] fix(react-utils): useOnElementResize always invokes callback in setTimeout to avoid resize observer error --- .../src/hooks/useOnElementResize.ts | 63 +++++++++---------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/packages/react-utils/src/hooks/useOnElementResize.ts b/packages/react-utils/src/hooks/useOnElementResize.ts index b40ef0e74b..26751e2398 100644 --- a/packages/react-utils/src/hooks/useOnElementResize.ts +++ b/packages/react-utils/src/hooks/useOnElementResize.ts @@ -16,40 +16,37 @@ export function useOnElementResize( useLayoutEffect(() => { const element = unwrapRefValue(refOrElement) + if (!element) { + return + } + if (!(element instanceof HTMLElement)) { + throw new Error('Exhaustive error: Expecting element to be instance of HTMLElement') + } + + let timeoutID: number | undefined = undefined + + function debouncedOnChange([entry]: ResizeObserverEntry[]) { + const timeStamp = Date.now() + const delta = timeStamp - lastTimeStamp.current + + clearTimeout(timeoutID) + const timeoutFinal = delta > timeout ? 0 : timeout + + timeoutID = setTimeout(() => { + const message = timeoutFinal > 0 ? 'element.resize:debounced' : 'element.resize:immediate' + scopedConsoleRef.current.warned(message, null) + callbackRef.current(entry) + lastTimeStamp.current = timeStamp + }, timeoutFinal) + } + + const resizeObserver = new ResizeObserver(debouncedOnChange) + + resizeObserver.observe(element, { box }) - if (element) { - if (element instanceof HTMLElement) { - let timeoutID: number | undefined = undefined - - function debouncedOnChange([entry]: ResizeObserverEntry[]) { - const timeStamp = Date.now() - const delta = timeStamp - lastTimeStamp.current - - if (delta > timeout) { - scopedConsoleRef.current.warned('element.resize:immediate', null) - callbackRef.current(entry) - lastTimeStamp.current = timeStamp - } else { - clearTimeout(timeoutID) - timeoutID = setTimeout(() => { - scopedConsoleRef.current.warned('element.resize:debounced', null) - callbackRef.current(entry) - lastTimeStamp.current = timeStamp - }, timeout) - } - } - - const resizeObserver = new ResizeObserver(debouncedOnChange) - - resizeObserver.observe(element, { box }) - - return () => { - clearTimeout(timeoutID) - resizeObserver.unobserve(element) - } - } else { - throw new Error('Exhaustive error: Expecting element to be instance of HTMLElement') - } + return () => { + clearTimeout(timeoutID) + resizeObserver.unobserve(element) } }, [box, refOrElement, scopedConsoleRef, timeout]) }