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>
</>
)
}
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.