Lazy loading react components is a way of deferring the rendering of components until they're needed. For below-the-fold content, it often makes sense to lazy load components, especially if they're detrimental to the performance if loaded upfront. I personally prefer to deal with lazy load heavy images and videos which appear below the fold. It helps increase core web vitals.
An intersection observer is a JavaScript API that allows you to monitor an element in your web page and note when it enters or exits the viewport. This can be useful for various purposes, such as triggering animations, lazy loading content, or implementing infinite scroll. The intersection observer API works by setting up a "callback" function that is executed whenever the target element intersects with the viewport, allowing you to respond to these events in your code.
The intersection observer API is supported by most modern web browsers, including Chrome, Firefox, Safari, and Edge. However, it may not be supported by older browsers or some mobile browsers. You can check the specific browser support for the intersection observer API on caniuse.com, which tracks browser support for different web technologies. If your target browser doesn't support it, you can polyfill (add support for) the API in order to use it in your code.
To use the intersection observer API in React, you can use the useRef
hook to create a reference to the element you want to monitor and the useEffect
hook to set up the observer. Here is an example of how you might do this:
function MyComponent() {
// Create a reference to the element that we want to observe
const targetElement = useRef(null);
const [isInView, setIsInView] = useState(false);
// Set up the intersection observer when the component mounts
useEffect(() => {
const observer = new IntersectionObserver(onIntersection, {});
observer.observe(targetElement.current);
// Clean up the observer when the component unmounts
return () => observer.unobserve(targetElement.current);
}, []);
// This is the callback function that is executed whenever the
// target element intersects with the viewport
function onIntersection(entries) {
// Do something with the intersection data, such as triggering
// an animation or lazy loading content
setIsInView(true);
}
return (
<div ref={targetElement}>{isInView ? <VeryHeavyComponent /> : null}</div>
);
}
In this example, we used the useRef
hook to create a reference to the element we want to observe and the useEffect
hook to set up the intersection observer when the component mounts. When the target element intersects with the viewport, the onIntersection
callback function is executed, allowing you to respond to the event in your code.
Make sure to clean up the IntersectionObserver
you subscribed in useEffect
. It's an important optimization of useEffect.
The react-intersection-observer
package is a wrapper around the IntersectionObserver API and makes lazy loading less verbose and easy-peasy. Let's take a look at an example:
const Video = (props) => {
const { ref, inView } = useInView({
triggerOnce: true,
fallbackInView: true,
});
return <div ref={ref}>{inView ? <video {...props} /> : null}</div>;
};
In this example, the Video
component is a wrapper around HTML's native video
element. We only render video
when it is in the viewport. It helps boost the performance of the page and core web vitals. You can pass various configurations to the useInView
hook as described in the documentation. For example, you can specify a threshold value to control when the component should be considered visible or add a root margin to adjust the boundaries of the viewport.
In conclusion, using the IntersectionObserver API or react-intersection-observer
package allows us to implement lazy loading in React components. This can improve the performance of our application by delaying the rendering of heavy components until they are actually needed. By using the useInView
hook and monitoring when a component enters the viewport, we can efficiently lazy load our components and improve the user experience.
Also published here.