Blog>
Snippets

Optimizing Large Datasets with Lazy Loading in React TanStack Table

Demonstrate how to implement lazy loading of data in React TanStack Table to optimize the performance when working with large datasets and faceted search.
import { useTable, useAsyncDebounce } from '@tanstack/table-core';
import { useEffect, useState } from 'react';

function fetchData({ pageIndex, pageSize, globalFilter }) {
  // simulate an API call
  return new Promise(resolve => {
    setTimeout(() => {
      // Mocked API response
      const startRow = pageIndex * pageSize;
      const endRow = startRow + pageSize;
      // Filter data based on globalFilter, then slice for pagination
      resolve(fakeDatabase.filter(row => row.name.includes(globalFilter)).slice(startRow, endRow));
    }, 1000);
  });
}
Defines a mock fetchData function to simulate fetching paginated and filtered data from an API or database. It accepts an object with pageIndex, pageSize, and globalFilter as parameters.
const [data, setData] = useState([]);
const [pageCount, setPageCount] = useState(0);
const [loading, setLoading] = useState(false);
const fetchIdRef = useRef(0);

const {
  getTableProps,
  getTableBodyProps,
  headerGroups,
  rows,
  prepareRow,
  // Fetch the state defined for pagination
  state: { pageIndex, pageSize, globalFilter },
  // Use 'setGlobalFilter' from useAsyncDebounce for efficient filtering
  setGlobalFilter,
} = useTable(
  {
    columns,
    data,
    initialState: { pageIndex: 0 },
    manualPagination: true, // Tell the table you'll handle pagination manually
    pageCount: pageCount,
  },
  useGlobalFilter, // Use the useGlobalFilter hook
  usePagination
);
Initializes the table instance with the useTable hook. Specifies columns and data for the table, along with setting up manual pagination and filtering. The state includes pageIndex, pageSize, and globalFilter for controlling pagination and global filtering.
useEffect(() => {
  const fetchDataAsync = async () => {
    setLoading(true);
    const fetchId = ++fetchIdRef.current;
    const result = await fetchData({ pageIndex, pageSize, globalFilter });
    if (fetchId === fetchIdRef.current) {
      setData(result.items);
      setPageCount(Math.ceil(result.total / pageSize));
      setLoading(false);
    }
  };

  fetchDataAsync();
}, [pageIndex, pageSize, globalFilter]);
Uses the useEffect hook to fetch data asynchronously whenever the pageIndex, pageSize, or globalFilter changes. Uses a fetchIdRef to ensure only the latest request updates the state to prevent race conditions.
const onSearchChange = useAsyncDebounce(value => {
  setGlobalFilter(value || undefined);
}, 200);
Utilizes useAsyncDebounce to wrap setGlobalFilter, introducing a 200ms delay before applying the filter. This helps in reducing the frequency of calls made to filter the data as the user types.