Blog>
Snippets

Server-side Data Fetching with Next.js and Lazy Load

Implement lazy loading data from the server-side in a Next.js app when a certain UI element is in view or an action is taken.
import { useState } from 'react';
import useSWR from 'swr';

// Function to fetch data (could be any async API call)
const fetchData = async (url) => {
  const response = await fetch(url);
  return response.json();
};
Define a fetchData function to make an API call and utilize useSWR hook for data fetching and caching.
import { useEffect, useRef, useState } from 'react';

const LazyLoadComponent = () => {
  // State to store our data
  const [data, setData] = useState(null);

  // State to track if we should load the data
  const [load, setLoad] = useState(false);

  // Ref for the element we want to watch
  const elementRef = useRef();

  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        // Check if element is in view
        if (entries[0].isIntersecting) {
          setLoad(true);
        }
      },
      { threshold: 0.1 }
    );

    // Start observing the element
    if (elementRef.current) {
      observer.observe(elementRef.current);
    }

    // Clean up observer on component unmount
    return () => observer.disconnect();
  }, []);
LazyLoadComponent uses an IntersectionObserver to check if the component's ref (elementRef) is in view. If so, it sets 'load' state to true.
const { data: serverData, error } = useSWR(load ? '/api/data' : null, fetchData);

  useEffect(() => {
    if (serverData) {
      setData(serverData);
    }
  }, [serverData]);
Use the useSWR hook with the 'load' state to manage when to fetch the data. If 'load' is true, the API call is made; otherwise, it is skipped.
return (
    <div>
      {error && <div>Failed to load data.</div>}
      {!data && <div ref={elementRef}>Loading...</div>}
      {data && (
        // Render your data here
        <div>{JSON.stringify(data, null, 2)}</div>
      )}
    </div>
  );
};

export default LazyLoadComponent;
Render the LazyLoadComponent, showing a 'Loading...' message until the data is fetched, upon which the data is rendered.