@@ -98,71 +98,66 @@ function checkIsVisible(
9898 return isVisible ;
9999}
100100
101- export default function useVisibilitySensor (
102- nodeRef ,
103- {
104- active = true ,
105- onChange,
106- partialVisibility = false ,
107- minTopValue = 0 ,
108- scrollCheck = false ,
109- scrollDelay = 250 ,
110- scrollThrottle = - 1 ,
111- resizeCheck = false ,
112- resizeDelay = 250 ,
113- resizeThrottle = - 1 ,
114- intervalCheck = true ,
115- intervalDelay = 100 ,
116- delayedCall = false ,
117- offset = { } ,
118- containment = null
119- }
120- ) {
101+ export default function useVisibilitySensor ( {
102+ active = true ,
103+ onChange,
104+ partialVisibility = false ,
105+ minTopValue = 0 ,
106+ scrollCheck = false ,
107+ scrollDelay = 250 ,
108+ scrollThrottle = - 1 ,
109+ resizeCheck = false ,
110+ resizeDelay = 250 ,
111+ resizeThrottle = - 1 ,
112+ intervalCheck = true ,
113+ intervalDelay = 100 ,
114+ delayedCall = false ,
115+ offset = { } ,
116+ containment = null
117+ } ) {
118+ const nodeRef = useRef ( ) ;
121119 const debounceCheckRef = useRef ( ) ;
122120 const intervalRef = useRef ( ) ;
123- const [ isVisible , setIsVisible ] = useState ( false ) ;
121+ const [ isVisible , setIsVisible ] = useState ( null ) ;
124122 const [ visibilityRect , setVisibilityRect ] = useState ( { } ) ;
125123
126124 const getContainer = useCallback ( ( ) => containment || window , [ containment ] ) ;
127125
128126 // Check if the element is within the visible viewport
129- const visibilityCheck = useCallback (
130- ( ) => {
131- const el = nodeRef && nodeRef . current ;
132- // if the component has rendered to null, dont update visibility
133- if ( ! el ) {
134- return ;
135- }
127+ const visibilityCheck = useCallback ( ( ) => {
128+ const el = nodeRef && nodeRef . current ;
129+ // if the component has rendered to null, dont update visibility
130+ if ( ! el ) {
131+ return ;
132+ }
136133
137- const rect = normalizeRect ( roundRectDown ( el . getBoundingClientRect ( ) ) ) ;
138- const containmentRect = getContainmentRect ( containment , offset ) ;
139- const nextVisibilityRect = getVisibilityRect ( rect , containmentRect ) ;
140- const nextIsVisible = checkIsVisible (
141- rect ,
142- containmentRect ,
143- nextVisibilityRect ,
144- partialVisibility ,
145- minTopValue
146- ) ;
147-
148- // notify the parent when the value changes
149- if ( isVisible !== nextIsVisible ) {
150- setIsVisible ( nextIsVisible ) ;
151- setVisibilityRect ( nextVisibilityRect ) ;
152- if ( onChange ) onChange ( nextIsVisible ) ;
153- }
154- } ,
155- [
156- isVisible ,
157- offset ,
158- containment ,
134+ const rect = normalizeRect ( roundRectDown ( el . getBoundingClientRect ( ) ) ) ;
135+ const containmentRect = getContainmentRect ( containment , offset ) ;
136+ const nextVisibilityRect = getVisibilityRect ( rect , containmentRect ) ;
137+ const nextIsVisible = checkIsVisible (
138+ rect ,
139+ containmentRect ,
140+ nextVisibilityRect ,
159141 partialVisibility ,
160- minTopValue ,
161- onChange ,
162- setIsVisible ,
163- setVisibilityRect
164- ]
165- ) ;
142+ minTopValue
143+ ) ;
144+
145+ // notify the parent when the value changes
146+ if ( isVisible !== nextIsVisible ) {
147+ setIsVisible ( nextIsVisible ) ;
148+ setVisibilityRect ( nextVisibilityRect ) ;
149+ if ( onChange ) onChange ( nextIsVisible ) ;
150+ }
151+ } , [
152+ isVisible ,
153+ offset ,
154+ containment ,
155+ partialVisibility ,
156+ minTopValue ,
157+ onChange ,
158+ setIsVisible ,
159+ setVisibilityRect
160+ ] ) ;
166161
167162 const addEventListener = useCallback (
168163 ( target , event , delay , throttle ) => {
@@ -209,77 +204,69 @@ export default function useVisibilitySensor(
209204 [ visibilityCheck ]
210205 ) ;
211206
212- useEffect (
213- ( ) => {
214- function watch ( ) {
215- if ( debounceCheckRef . current || intervalRef . current ) {
216- return ;
217- }
218-
219- if ( intervalCheck ) {
220- intervalRef . current = setInterval ( visibilityCheck , intervalDelay ) ;
221- }
222-
223- if ( scrollCheck ) {
224- addEventListener (
225- getContainer ( ) ,
226- "scroll" ,
227- scrollDelay ,
228- scrollThrottle
229- ) ;
230- }
207+ useEffect ( ( ) => {
208+ function watch ( ) {
209+ if ( debounceCheckRef . current || intervalRef . current ) {
210+ return ;
211+ }
231212
232- if ( resizeCheck ) {
233- addEventListener ( window , "resize" , resizeDelay , resizeThrottle ) ;
234- }
213+ if ( intervalCheck ) {
214+ intervalRef . current = setInterval ( visibilityCheck , intervalDelay ) ;
215+ }
235216
236- // if dont need delayed call, check on load ( before the first interval fires )
237- ! delayedCall && visibilityCheck ( ) ;
217+ if ( scrollCheck ) {
218+ addEventListener ( getContainer ( ) , "scroll" , scrollDelay , scrollThrottle ) ;
238219 }
239220
240- if ( active ) {
241- watch ( ) ;
221+ if ( resizeCheck ) {
222+ addEventListener ( window , "resize" , resizeDelay , resizeThrottle ) ;
242223 }
243224
244- // stop any listeners and intervals on props change and re-registers
245- return ( ) => {
246- if ( debounceCheckRef . current ) {
247- const debounceCheck = debounceCheckRef . current ;
248- // clean up event listeners and their debounce callers
249- for ( let debounceEvent in debounceCheck ) {
250- if ( debounceCheck . hasOwnProperty ( debounceEvent ) ) {
251- const debounceInfo = debounceCheck [ debounceEvent ] ;
252-
253- clearTimeout ( debounceInfo . getLastTimeout ( ) ) ;
254- debounceInfo . target . removeEventListener (
255- debounceEvent ,
256- debounceInfo . fn
257- ) ;
258-
259- debounceCheck [ debounceEvent ] = null ;
260- }
261- }
262- }
263- debounceCheckRef . current = null ;
225+ // if dont need delayed call, check on load ( before the first interval fires )
226+ ! delayedCall && visibilityCheck ( ) ;
227+ }
228+
229+ if ( active ) {
230+ watch ( ) ;
231+ }
264232
265- if ( intervalRef . current ) {
266- intervalRef . current = clearInterval ( intervalRef . current ) ;
233+ // stop any listeners and intervals on props change and re-registers
234+ return ( ) => {
235+ if ( debounceCheckRef . current ) {
236+ const debounceCheck = debounceCheckRef . current ;
237+ // clean up event listeners and their debounce callers
238+ for ( let debounceEvent in debounceCheck ) {
239+ if ( debounceCheck . hasOwnProperty ( debounceEvent ) ) {
240+ const debounceInfo = debounceCheck [ debounceEvent ] ;
241+
242+ clearTimeout ( debounceInfo . getLastTimeout ( ) ) ;
243+ debounceInfo . target . removeEventListener (
244+ debounceEvent ,
245+ debounceInfo . fn
246+ ) ;
247+
248+ debounceCheck [ debounceEvent ] = null ;
249+ }
267250 }
268- } ;
269- } ,
270- [
271- active ,
272- scrollCheck ,
273- scrollDelay ,
274- scrollThrottle ,
275- resizeCheck ,
276- resizeDelay ,
277- resizeThrottle ,
278- intervalCheck ,
279- intervalDelay ,
280- visibilityCheck
281- ]
282- ) ;
251+ }
252+ debounceCheckRef . current = null ;
283253
284- return { isVisible, visibilityRect } ;
254+ if ( intervalRef . current ) {
255+ intervalRef . current = clearInterval ( intervalRef . current ) ;
256+ }
257+ } ;
258+ } , [
259+ active ,
260+ scrollCheck ,
261+ scrollDelay ,
262+ scrollThrottle ,
263+ resizeCheck ,
264+ resizeDelay ,
265+ resizeThrottle ,
266+ intervalCheck ,
267+ intervalDelay ,
268+ visibilityCheck
269+ ] ) ;
270+
271+ return { nodeRef, isVisible, visibilityRect } ;
285272}
0 commit comments