1
1
import React from 'react'
2
2
3
- import useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect'
4
-
5
- export type HasBoundingClientRect = {
6
- getBoundingClientRect : ( ) => DOMRect
7
- }
8
-
9
3
export default function useRect (
10
- node : HasBoundingClientRect | null | undefined ,
4
+ element : Element | null | undefined ,
11
5
enabled : boolean
12
6
) {
13
- const [ element , setElement ] = React . useState ( node )
7
+ const rerender = React . useReducer ( ( ) => ( { } ) , [ ] ) [ 1 ]
14
8
15
- let [ rect , setRect ] = React . useState < DOMRect > ( {
16
- width : 0 ,
17
- height : 0 ,
18
- } as DOMRect )
9
+ const rectRef = React . useRef < DOMRect > ( )
19
10
20
- const rectRef = React . useRef ( rect )
11
+ const measure = React . useCallback ( ( ) => {
12
+ if ( element ) {
13
+ rectRef . current = element . getBoundingClientRect ( )
14
+ }
15
+ } , [ element ] )
16
+
17
+ if ( ! rectRef . current ) {
18
+ measure ( )
19
+ }
21
20
22
- rectRef . current = rect
21
+ React . useEffect ( ( ) => {
22
+ if ( ! element || ! enabled ) {
23
+ return
24
+ }
23
25
24
- useIsomorphicLayoutEffect ( ( ) => {
25
- if ( node !== element ) {
26
- setElement ( node )
26
+ const cb = ( ) => {
27
+ measure ( )
28
+ rerender ( )
27
29
}
28
- } )
29
30
30
- useIsomorphicLayoutEffect ( ( ) => {
31
- if ( enabled && element ) {
32
- setRect ( element . getBoundingClientRect ( ) )
31
+ document . addEventListener ( 'scroll' , cb )
32
+
33
+ return ( ) => {
34
+ document . removeEventListener ( 'scroll' , cb )
33
35
}
34
- } , [ element , enabled ] )
36
+ } , [ element , enabled , measure , rerender ] )
35
37
36
38
React . useEffect ( ( ) => {
37
39
if ( ! element || ! enabled ) {
38
40
return
39
41
}
40
42
41
- const observer = new ResizeObserver ( ( entries ) => {
42
- setRect ( entries [ 0 ] ?. contentRect )
43
+ measure ( )
44
+ rerender ( )
45
+
46
+ const observer = new ResizeObserver ( entries => {
47
+ measure ( )
48
+ rerender ( )
43
49
} )
44
50
45
51
observer . observe ( element as Element )
46
52
47
53
return ( ) => {
48
54
observer . unobserve ( element as Element )
49
55
}
50
- } , [ element , enabled ] )
56
+ } , [ element , enabled , measure , rerender ] )
51
57
52
58
// const resolvedRect = React.useMemo(() => {
53
59
// if (!element || !(element as Element).tagName) {
@@ -74,5 +80,5 @@ export default function useRect(
74
80
// }
75
81
// }, [element, rect])
76
82
77
- return rect
83
+ return rectRef . current
78
84
}
0 commit comments