next.jsfetch-api

How to update parameter in API URL when clicking "next" button


I am building a website based on the Jikan API. I am able to fetch the data I need. However, as there are 1000s of entries, they are behind pagination, which I can access this info fine.

What I want to be able to accomplish is to update the API parameter based on the click of a button to cycle through pages.

I have been able to add the functionality for the button and it works as intended, however, the API URL does not update, so I only ever have access to the first page of results.

My server component to fetch the API is below:

import NextPage from './../components/PaginationButtons';

export default async function AnimeList() {
    let current_page = 1
    let data = await fetch(`https://api.jikan.moe/v4/anime?page=${current_page}`)
    let anime = await data.json()

    const total_pages = anime.pagination.last_visible_page
    const page = anime.pagination.current_page



    return (
        <div>
             
            <div className="flex flex-col flex-wrap">
                <ul>
                    {anime.data.map(a => (
                        <li>{a.title}</li>
                    ))}
                </ul>
            </div>
            
            <NextPage
                current_page={current_page}
                total_pages={total_pages}
                page={page}
            />  
        </div>
    )
}

My client component for the button is below:

"use client"

export default function NextPage({ current_page, total_pages }) {
    
    return (
        <>
            <div className="join">
                <button className="join-item btn" onClick={() => current_page--}>Previous Page</button>
                <p>{current_page} <span>of</span> {total_pages}</p>
                <button className="join-item btn" onClick={() => current_page++}>Next Page</button>
            </div>
        </>
    )
}

Solution

  • The API URL never updates because the value of current_page never changes. You are trying to change it with the onClick handler functions in the NextPage component, but you should never directly modify a prop passed to a React component within that component. The React way to do what you want is with the useState hook and passing a function to NextPage that will update the value in the parent component AnimeList. Here is how you can do it:

    Change the AnimeList component file to:

    "use client"
    
    import NextPage from './../components/PaginationButtons';
    import { useState } from 'react';
    
    export default function AnimeList() {
      const [current_page, set_current_page] = useState(1)
      const [anime, setAnime] = useState(null)
    
      const getAnime = async () => {
        let response = await fetch(`https://api.jikan.moe/v4/anime?page=${current_page}`)
        setAnime(await response.json())
      }
      getAnime()
    
      if (!anime) return false
    
      const total_pages = anime.pagination.last_visible_page
      const page = anime.pagination.current_page
    
      return (
        <div>
          {/* ... */}
          <NextPage
            current_page={current_page}
            total_pages={total_pages}
            page={page}
            set_current_page={set_current_page}
          /> 
        </div>
      )
    }
    

    Change the NextPage component file to:

    "use client"
    
    export default function NextPage({
      current_page,
      total_pages,
      set_current_page,
    }) {    
        return (
            <>
                <div className="join">
                    <button
                      className="join-item btn"
                      onClick={() => set_current_page((current_page - 1) || 1)}
                    >
                      Previous Page
                    </button>
                    <p>{current_page} <span>of</span> {total_pages}</p>
                    <button
                      className="join-item btn"
                      onClick={() => set_current_page(current_page + 1)}
                    >
                      Next Page
                    </button>
                </div>
            </>
        )
    }
    

    Note that you must now include the "use client" directive in the AnimeList component file. If AnimeList is server-side rendered it will not be able to pass the set_current_page function to the NextPage client component, because the function cannot be serialized.