
Load More Button with NextJS 14 and Sanity
Google recently announced theywere going to kill the infinite scrollfeature on their search pages. That finally motivated to code a load more button feature for the index page. It used to load everything all at once, but now that I have a bit more content, it's good to have this feature for a better overall experience.
What needed to be done:
Modify my getAllArticles function to accept pagination parameters
Modify the index page to only display the first 5 articles
Add a load more button that will be rendered client-side with the following behavior:
First time rendered: just show the button
Once pressed, render the PostLoop component with the right article and re-render the button at the bottom
If no more articles, display some text to tell the user you're at the bottom of the list
Code snippets
typescript"use client"; import React, { useState } from "react"; import PostLoop from "./PostLoop"; import { getAllArticles } from "@/utils/sanity"; import { PostType } from "@/types/post"; const LoadMoreButton = () => { // State variables to keep track of the current page and the new page of articles const [currentPage, setCurrentPage] = useState<number>(3); const [newPage, setNewPage] = useState<PostType[]>([]); // Function to fetch the next page of articles when the button is clicked const onClick = async () => { // Fetch the next page of articles using the getAllArticles function const newPosts: PostType[] = await getAllArticles({ page: currentPage, pageSize: 3, }); // Append the new articles to the existing newPage array setNewPage([...newPage, ...newPosts]); // If newPosts is not empty, increment the currentPage by 1 // Otherwise, set the currentPage to 0 to indicate that there are no more articles to load if (newPosts.length !== 0) { setCurrentPage(currentPage + 1); } else { setCurrentPage(0); } }; return ( <> {/* Render the PostLoop component with the newPage array */} <PostLoop posts={newPage} /> {/* Render the load more button or the "no more articles" message based on the currentPage */} <div className="flex flex-col justify-center items-center"> {currentPage !== 0 && ( <button className="bg-violet-700 text-white py-2 px-4 rounded" onClick={onClick} > Load More Articles </button> )} {currentPage === 0 && ( <h2 className="mb-2 text-2xl text-black"> No more articles to load 😢 </h2> )} </div> </> ); }; export default LoadMoreButton;
And the updated utility function
typescriptconst getAllArticles = async ({ page = -1, pageSize = 0, }: { page?: number; pageSize?: number } = {}) => { let skip: number = 0; let filter: string = ""; if (page > 0 && pageSize > 0) { skip = (page - 1) * pageSize; // Calculate the number of items to skip filter = `[${skip}...${skip + pageSize}]`; // Add the filter to the query } const items = await mySanityClient.fetch( `*[_type == "post"]{ title, _id, _createdAt, publishedAt, description, body, mainImage, "slug": slug.current } | order(publishedAt desc)${filter}` ); return items; };