Blog>
Snippets

Optimizing Infinite Scroll Performance

Highlights techniques for optimizing the performance of an infinite scroll feature, including debouncing scroll events and efficiently managing the cache with React Query.
import { useInfiniteQuery } from 'react-query';
import { useEffect, useState } from 'react';

function useInfinitePosts() {
  return useInfiniteQuery(
    'posts',
    async ({ pageParam = 1 }) => {
      const response = await fetch(`/api/posts?page=${pageParam}`);
      return response.json();
    },
    {
      getNextPageParam: (lastPage, pages) => lastPage.nextPage ?? false
    }
  );
}
This code snippet demonstrates how to fetch data in chunks using React Query's 'useInfiniteQuery' hook. Each chunk corresponds to a 'page' of data from the API. The 'getNextPageParam' returns the value for the next page, or false if there are no more pages.
import { useRef, useCallback } from 'react';
import { useIntersectionObserver } from './useIntersectionObserver';

const InfiniteScrollComponent = ({ data, fetchNextPage }) => {
  const loadMoreRef = useRef();

  useIntersectionObserver({
    target: loadMoreRef,
    onIntersect: fetchNextPage,
    enabled: data?.hasNextPage,
  });

  return (
    <div>
      {data.pages.map(page => (
        <React.Fragment key={page.key}>
          {page.items.map(item => <div key={item.id}>{item.title}</div>)}
        </React.Fragment>
      ))}
      <div ref={loadMoreRef}>Load More</div>
    </div>
  );
}
This code implements the UI component and utilizes an IntersectionObserver hook (`useIntersectionObserver`) to detect when the `Load More` div becomes visible on screen, triggering `fetchNextPage`. The `ref` attached to the `Load More` div moves down with each data fetch, ensuring smooth infinite scrolling.
function debounce(func, wait) {
  let timeout;

  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };

    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
}
This is a debounce function, used to limit the number of times a function (like scrolling events) can be executed over time. This can enhance performance by reducing the number of API calls or heavy computations when scrolling rapidly.