Skip to content

Commit 9e5068d

Browse files
committed
fix useResizeObserver
1 parent 3e0a121 commit 9e5068d

File tree

2 files changed

+56
-18
lines changed

2 files changed

+56
-18
lines changed

packages/react/src/use-resize-observer/index.ts

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { useCallback, useEffect, useRef, useState } from 'react'
1+
import {
2+
type DependencyList,
3+
useCallback,
4+
useEffect,
5+
useRef,
6+
useState,
7+
} from 'react'
28
import debounce from 'just-debounce-it'
39

410
let defaultDebounceDelay = 500
@@ -19,16 +25,21 @@ function setDebounce(delay: number) {
1925
* @returns {array} [setResizeObserverRef, options.lazy ? getEntryRef : entry]
2026
*/
2127

22-
const callbacksMap = new Map<Element, (entry: ResizeObserverEntry) => void>()
28+
const callbacksMap = new Map<
29+
Element,
30+
((entry: ResizeObserverEntry) => void)[]
31+
>()
2332

2433
let sharedObserver: ResizeObserver | null = null
2534
function getSharedObserver() {
2635
if (!sharedObserver) {
2736
sharedObserver = new ResizeObserver((entries) => {
2837
for (const entry of entries) {
29-
const callback = callbacksMap.get(entry.target)
30-
if (callback) {
31-
callback(entry)
38+
const callbacks = callbacksMap.get(entry.target)
39+
if (callbacks) {
40+
for (const cb of callbacks) {
41+
cb(entry)
42+
}
3243
}
3344
}
3445
})
@@ -43,22 +54,26 @@ function observeElement(
4354
) {
4455
if (!el) return () => {}
4556

46-
let isFirstCall = true
47-
const debouncedCallback = debounce(callback, debounceDelay)
48-
callbacksMap.set(el, (entry: ResizeObserverEntry) => {
49-
if (isFirstCall) {
50-
callback(entry)
51-
} else {
52-
debouncedCallback(entry)
53-
}
54-
isFirstCall = false
55-
})
57+
const debouncedCallback = debounce(callback, debounceDelay, true)
58+
59+
const callbacks = callbacksMap.get(el) || []
60+
callbacks.push(debouncedCallback)
61+
callbacksMap.set(el, callbacks)
5662
const sharedObserver = getSharedObserver()
5763
sharedObserver.observe(el)
5864

5965
return () => {
60-
callbacksMap.delete(el)
61-
sharedObserver.unobserve(el)
66+
const callbacks = callbacksMap.get(el)
67+
if (callbacks) {
68+
const index = callbacks.indexOf(debouncedCallback)
69+
if (index > -1) {
70+
callbacks.splice(index, 1)
71+
}
72+
if (callbacks.length === 0) {
73+
callbacksMap.delete(el)
74+
sharedObserver.unobserve(el)
75+
}
76+
}
6277
if (callbacksMap.size === 0) {
6378
sharedObserver.disconnect()
6479
}
@@ -75,7 +90,7 @@ export function useResizeObserver<L extends boolean = false>(
7590
debounce?: number
7691
callback?: (entry: ResizeObserverEntry) => void
7792
} = {},
78-
deps: any[] = []
93+
deps: DependencyList = []
7994
): [
8095
(element: HTMLElement | null) => void,
8196
L extends true

playground/react/app.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ export default function App() {
5656
},
5757
})
5858

59+
const rect2Ref = useRef<HTMLElement>(null)
60+
const [setRectRef2, rect2, setRectWrapperRef2] = useRect({
61+
// lazy: true,
62+
callback(rect) {
63+
if (rect2Ref.current) {
64+
const { width, height, top, left } = rect
65+
66+
rect2Ref.current.textContent = `width: ${width}px - height: ${height}px - top: ${top}px - left: ${left}px`
67+
}
68+
},
69+
})
70+
5971
const [setIntersectionObserverRef, entry] = useIntersectionObserver()
6072

6173
useDebouncedEffect(
@@ -143,6 +155,17 @@ export default function App() {
143155
>
144156
useRect: <span ref={rectRef} />
145157
</div>
158+
<div
159+
ref={setRectRef2}
160+
style={{
161+
width: '20vw',
162+
height: '100px',
163+
border: '1px solid green',
164+
padding: '20px',
165+
}}
166+
>
167+
useRect: <span ref={rect2Ref} />
168+
</div>
146169
<div ref={setIntersectionObserverRef}>
147170
useIntersectionObserver:{' '}
148171
<span>{entry?.isIntersecting ? 'true' : 'false'}</span>

0 commit comments

Comments
 (0)