Skip to content

Instantly share code, notes, and snippets.

@FredrikAugust
Created May 27, 2019 15:22
Show Gist options
  • Save FredrikAugust/f6ec2a2ceb1bf3f5e90dc5fc07524e1f to your computer and use it in GitHub Desktop.
Save FredrikAugust/f6ec2a2ceb1bf3f5e90dc5fc07524e1f to your computer and use it in GitHub Desktop.
usePagination
import React from 'react';
interface User {
id: number;
email: string;
first_name: string;
last_name: string;
avatar: string;
}
// This is the function which takes the previous request if there was one, and the page to get, and returns the new Request for the next page
type Pager = (page: number, previousRequest?: Response) => Request;
type MapResToType<T> = (res: Response) => Promise<T[]>;
function usePagination<T>(
pager: Pager,
mapResToType: MapResToType<T>,
initialPage: number = 1
): [T[], () => Promise<void>, boolean] {
const [data, setData] = React.useState<T[]>([]);
const [page, setPage] = React.useState(initialPage);
// We want to check if the source we're retrieving from no longer returns any new items when requesting the next page
const [depleted, setDepleted] = React.useState(false);
async function fetchNewPage() {
await setPage(page + 1); // This won't actually be the value of page until the next call due to async
const result = await mapResToType(await fetch(pager(page)));
if (!result.length) {
setDepleted(true);
}
setData([...data, ...result]); // This is actually the page value from before the call
}
return [data, fetchNewPage, depleted];
}
const App = () => {
const [pages, getMorePages, depleted] = usePagination<User>(
(page, _previousRequest) => new Request(`https://reqres.in/api/users?page=${page}`),
async (res) => (await (await res.json()).data)
);
return (
<>
<h1>Welcome to my pagination hook demo website.</h1>
<p>This took longer than expected, so please stick around.</p>
{pages.map(e => (
<div key={e.id}>
<img src={e.avatar} alt="Avatar" />
<h3>[{e.id}] {e.first_name} {e.last_name} &lt;{e.email}&gt;</h3>
</div>
))}
<button disabled={depleted} onClick={async () => await getMorePages()}>Get</button>
</>
);
}
export default App;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment