Skip to main content
Version: v8.0.0

Infinite Scroll

Infinite scroll is a popular pattern for loading and displaying a large number of items without traditional pagination. As the user scrolls down, new items are fetched and added to the end of the list. While Hyper-fetch doesn't have a dedicated useInfiniteScroll hook out-of-the-box, you can easily implement this pattern by composing useSubmit to load more data on demand.

What you'll learn
  1. How to implement a "Load More" feature for paginated data.
  2. How to use useSubmit to manually trigger fetching for the next page.
  3. How to append new data to an existing list in React state.
  4. How to manage loading states for a better user experience.

Implementation with useSubmit

A clean way to implement infinite scroll is to use the useSubmit hook to fetch new pages when the user clicks a "Load More" button. This gives us precise control over when data is fetched.

function InfinitePostList() {
const [posts, setPosts] = React.useState([]);
const [page, setPage] = React.useState(1);
const [allLoaded, setAllLoaded] = React.useState(false);

// We use useSubmit to manually trigger the fetch for the next page
const { submit, submitting } = useSubmit(getPosts);

const loadMore = async () => {
const { data: newPosts } = await submit({ queryParams: { page, limit: 5 } });

if (newPosts && newPosts.length > 0) {
setPosts((prevPosts) => [...prevPosts, ...newPosts]);
setPage((prevPage) => prevPage + 1);
} else {
setAllLoaded(true);
}
};

// Load the first page on component mount
React.useEffect(() => {
loadMore();
}, []);

return (
<div className="border rounded-md">
<ul className="divide-y divide-gray-200">
{posts.map((post) => (
<li key={post.id} className="p-4">
<p className="font-bold">{post.title}</p>
<p>{post.body}</p>
</li>
))}
</ul>

{submitting && <p className="text-center p-4">Loading...</p>}

{!allLoaded && (
<div className="p-4 flex justify-center">
<button
className="px-6 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:bg-gray-400"
onClick={loadMore}
disabled={submitting}
>
{submitting ? "Loading..." : "Load More"}
</button>
</div>
)}
{allLoaded && posts.length > 0 && <p className="text-center p-4 text-gray-500">You've reached the end!</p>}
</div>
);
}

How it Works

  1. We maintain a posts array in our state to hold all the items and a page number to track which page to fetch next.
  2. We use useSubmit because it allows us to trigger the request manually via the submit function. This is perfect for a "Load More" button.
  3. The loadMore function calls submit with the current page. The submit function is a promise, so we can await its result.
  4. Once we get the newPosts, we append them to our existing posts array and increment the page number for the next fetch.
  5. If the API returns an empty array, we know we've reached the end, and we can stop showing the "Load More" button.
  6. A useEffect hook is used to load the initial page of data when the component mounts.

This approach is robust and gives a great user experience by showing a growing list of items.


Congratulations!

You've learned how to build an infinite scroll feature with Hyper-fetch!

  • You can create a "Load More" pattern for large datasets using useSubmit.
  • You can manage paginated data from an API and display it in a single, growing list.
  • You can manually trigger data fetching for creating interactive data-driven UIs.