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) {
      { threshold: 0.1 }

    // Start observing the element
    if (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) {
  }, [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 (
      {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>

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