Lazy loading is a way for websites to load new data for the user to see without needing to click a button.
No scroll events
Plenty of lazy load tutorials use scroll events to determine whether or not your user has scrolled to the end of a container. It's a valid solution to use scroll events but I was thinking of an alternative.
Say hello to the Intersection Observer API. The Intersection Observer keeps track of when elements intersect with the given container. This is what we'll use to determine whether or not we've hit the bottom of our container.
useLazyLoad
Hook
The useLazyLoad
hook will be where we'll use the Intersection Observer. The hook will have 3 parameters -- triggerRef
, onGrabData
, and options
.
-
triggerRef
is our ref to our trigger element -
onGrabData
is the function that will be called to load more data -
options
is the options object that can be passed to the Intersection Observer constructor.
const useLazyLoad = (triggerRef, onGrabData, options) => {
...
}
Inside of a useEffect
, we'll create our observer.
useEffect(() => {
if (triggerRef.currrent) {
const observer = new IntersectionObserver(onIntersect, options)
observer.observe(triggerRef.current)
return () => {
observer.disconnect()
}
}
}, [triggerRef, onIntersect, options])
A couple of important things to note here are onIntersect
, observe()
and disconnect()
.
-
onIntersect
is a callback function called by the observer when the observed elements interact with the observer root. -
observe
is a function that makes an element something that the observer should be keeping track of. -
disconnect
is a cleanup function that stops the observer from observing.
onIntersect
The callback function required by the Intersection Observer receives entries
as its parameter.
const onIntersect = (entries) => {
const boundingRect = entries[0].boundingClientRect
const intersectionRect = entries[0].intersectionRect
if (intersectionRect.bottom - boundingRect.bottom <= 5) {
onGrabData(...)
}
}
entries
The entries
parameter is an array of IntersectionObserverEntry. The callback is called when one or more of the elements being observed intersects or stops intersecting against the root
.
triggerRef
The triggerRef
is an element that Intersection Observer will be keeping track of.
...
const triggerRef = useRef(null)
const { data } = useLayLoad(triggerRef, onGrabData, options)
...
return (
<section>
{data.map((item) => (
<div key={item.id}>
...
</div>
))}
<div ref={triggerRef} />
</section>
)
...
The trigger element will be found beneath the data which will push the trigger beyond the viewport. When the user scrolls down, the trigger will intersect with the viewport triggering the intersection observer callback.
Working Demo
Top comments (2)
Nice trick!. Not only for scroll event, but also applicable for many scenarios. Thank you!
Good piece. Really liked your approach.