Lazy Loading React Components using intersection observer
Tags: javascript, react, reactnative, webdev
Published: 2023-01-17 12:59:52

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 do lazy load heavy images and videos which appear below the fold. It helps increase [core web vitals](https://web.dev/vitals/).

## What is intersection observer?

An intersection observer is a JavaScript API that allows you to monitor when an element in your web page 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.

## Browser support for intersection observer

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](https://caniuse.com/mdn-api_intersectionobserver), which tracks browser support for different web technologies. If your target browser don't support it, you can polyfill (add support for) the API in order to use it in your code.

## Lazy Loading React Components using intersection observer (the hard way)

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:

```jsx
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](/blog/optimizing-useeffect-in-react)

## Lazy Loading React Components using intersection observer (the easy way)

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:

```jsx
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](https://www.npmjs.com/package/react-intersection-observer). 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.