Step Level Up
Effortless Infinite Loading and Load More in Next.js with TypeScript and SWR
M
Mahadev Mandal

· min read

Infinite Loading and Load More Functionality in Next.js with TypeScript and SWR

In modern web applications, infinite scrolling and "load more" functionality enhance user experience by seamlessly fetching data as users scroll or click to load more items. This tutorial will guide you through implementing these features in a Next.js application using TypeScript and SWR.

Setting Up the Project

1. Initialize a Next.js Project

First, create a new Next.js project if you haven't already:

npx create-next-app@latest my-nextjs-app --typescript
cd my-nextjs-app

2. Install Necessary Dependencies

Ensure you have SWR installed for data fetching:

npm install swr

Backend Setup

In this example, we'll use the JSONPlaceholder API to fetch posts. Create an API route to handle paginated requests.

/src/app/api/posts/route.ts

import { NextRequest, NextResponse } from "next/server";

// Using JSONPlaceholder for data 
export const GET = async (req: NextRequest) => {
  try {
    const res = await fetch('https://jsonplaceholder.typicode.com/posts');
    const allData: any[] = await res.json();
    const totalCount = allData.length;

    const searchParams = req.nextUrl.searchParams;
    const page = Number(searchParams.get('page'));
    const dataPerPage = Number(searchParams.get('dataPerPage'));
    const data = allData.slice(page * dataPerPage, (page + 1) * dataPerPage);

    return NextResponse.json(
      { message: 'Ok', success: true, data: data, totalCount },
      { status: 200 }
    );
  } catch (error: any) {
    return NextResponse.json(
      { message: error?.message, success: false },
      { status: 500 }
    );
  }
};

Frontend Setup

Create a page to fetch and display the posts with infinite scrolling and "load more" functionality.

/src/app/page.tsx

'use client'
import React, { useState } from 'react';
import useSWRInfinite from 'swr/infinite';

type PostType = {
  id: number;
  title: string;
  userId: number;
  body: string;
}

const fetchData = async (url: string) => {
  const response = await fetch(url);
  return response.json();
}

function HomePage() {
  const [dataPerPage, setDataPerPage] = useState(20);

  const getKey = (pageIndex: number, previousPageData: any) => {
    if (previousPageData && !previousPageData.data?.length) return null; // reached the end
    return `/api/posts?page=${pageIndex}&&dataPerPage=${dataPerPage}`;
  }

  const { data: result, setSize, size, mutate, isValidating, isLoading } = useSWRInfinite(getKey, fetchData);

  let posts: PostType[] = [];
  let totalCount = 0;
  if (result?.length) {
    result.forEach(item => {
      posts = [...posts, ...item.data || []];
    });
    totalCount = result[0].totalCount || 0;
  }

  const handleLoadMore = () => {
    setSize(size + 1);
  }

  if (isLoading) return <p>Loading...</p>;

  return (
    <div>
      <h1>All posts</h1>
      {posts?.map((item) => (
        <div
          key={item.id}
          style={{
            border: '1px solid grey',
            marginTop: 10,
            padding: 10
          }}
        >
          <h3>{item.title}</h3>
          <div dangerouslySetInnerHTML={{ __html: item.body }} />
        </div>
      ))}
      {totalCount > posts.length && <button onClick={handleLoadMore}>
        {isValidating ? 'Loading...' : 'Load more'}
      </button>}
    </div>
  );
}

export default HomePage;

Explanation

  1. API Route:

    • Fetch all posts from the JSONPlaceholder API.
    • Use query parameters to handle pagination (page and dataPerPage).
    • Slice the data array based on the current page and the number of items per page.
  2. Frontend Component:

    • useSWRInfinite is used to handle infinite loading.
    • The getKey function generates the API endpoint URL based on the current page index.
    • The handleLoadMore function increments the page size to load more data.
    • Posts are displayed in a simple list with a "Load more" button at the bottom.

Conclusion

By following this guide, you can implement efficient infinite loading and "load more" functionality in your Next.js application using TypeScript and SWR. This enhances the user experience by loading data as needed, reducing initial load times and improving overall performance.

Comments

Loading...

Mahadev Mandal

Written by Mahadev Mandal

I am a web developer with expertise in HTML, CSS, Tailwind, React.js, Next.js, Gatsby, API integration, WordPress, Netlify functions, the MERN stack, fullstack development, and NestJS.