Created
March 16, 2024 22:06
-
-
Save smakosh/84d90a91a4e89f746c04ea58abbebe67 to your computer and use it in GitHub Desktop.
Next.js Offset/limit pagination
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const LIMIT = 10; | |
export const RANGE = 5; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Launch } from "@/types/launch"; | |
import { LIMIT } from "@/app/_constants"; | |
import { HomeProps } from "@/app/_types/params"; | |
export const getLaunches = async ( | |
offset: HomeProps["searchParams"]["offset"] | |
) => { | |
const response = await fetch("https://api.spacexdata.com/v5/launches/query", { | |
method: "POST", | |
body: JSON.stringify({ | |
limit: LIMIT, | |
offset: offset ? Number(offset) * 10 : 20, | |
}), | |
}); | |
const data = await response.json(); | |
return { | |
launches: data.docs as Launch[], | |
currentPage: data.page, | |
total: data.totalPages, | |
}; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { unstable_noStore as noStore } from "next/cache"; | |
import { | |
Pagination, | |
PaginationContent, | |
PaginationEllipsis, | |
PaginationItem, | |
PaginationLink, | |
PaginationNext, | |
PaginationPrevious, | |
} from "@/components/ui/pagination"; | |
import { HomeProps } from "@/app/_types/params"; | |
import { getLaunches } from "@/app/_services/getLaunches"; | |
import { RANGE } from "@/app/_constants"; | |
const Launches = async ({ offset }: HomeProps["searchParams"]) => { | |
noStore(); | |
const { launches, currentPage, total } = await getLaunches(offset); | |
function* paginationGen() { | |
let i = 1; | |
let left = Math.max(1, currentPage - RANGE); | |
let right = Math.min(total, currentPage + RANGE); | |
// Is the current index displayable | |
const shouldDisplay = (at: number) => { | |
return at === 1 || at === total || (at >= left && at <= right); | |
}; | |
// The next index I should jump to based on my current position | |
const next = (at: number) => { | |
if (at == 1 || at == total) return at + 1; | |
if (at < left) return left; | |
if (at > right) return total; | |
return at + 1; | |
}; | |
while (i <= total) { | |
if (shouldDisplay(i)) { | |
yield i; | |
} else { | |
yield "..."; | |
} | |
i = next(i); | |
} | |
} | |
return ( | |
<> | |
<ul> | |
{launches.map((launch) => ( | |
<li key={launch.id}>{launch.name}</li> | |
))} | |
</ul> | |
<Pagination> | |
<PaginationContent> | |
<PaginationItem> | |
<PaginationPrevious | |
href={`/?offset=${currentPage - 1}`} | |
aria-disabled={currentPage === 1} | |
/> | |
</PaginationItem> | |
{Array.from(paginationGen()).map((item, i) => { | |
if (item === "...") { | |
return ( | |
<PaginationItem key={i}> | |
<PaginationEllipsis /> | |
</PaginationItem> | |
); | |
} | |
return ( | |
<PaginationItem key={`paginate-${i}`}> | |
<PaginationLink | |
href={`/?offset=${item}`} | |
aria-disabled={item === currentPage} | |
> | |
{item} | |
</PaginationLink> | |
</PaginationItem> | |
); | |
})} | |
<PaginationItem> | |
<PaginationNext | |
href={`/?offset=${currentPage + 1}`} | |
aria-disabled={currentPage === total} | |
/> | |
</PaginationItem> | |
</PaginationContent> | |
</Pagination> | |
</> | |
); | |
}; | |
export default Launches; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Suspense } from "react"; | |
import Launches from "./_components/launches"; | |
import { HomeProps } from "./_types/params"; | |
export default async function Home({ searchParams }: HomeProps) { | |
return ( | |
<div className="container"> | |
<h1>SpaceX launches</h1> | |
<Suspense | |
fallback={<h4>Fetching launches...</h4>} | |
key={searchParams.offset} | |
> | |
<Launches {...searchParams} /> | |
</Suspense> | |
</div> | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type HomeProps = { searchParams: { offset: string | null } }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment