Created
May 27, 2019 15:22
-
-
Save FredrikAugust/f6ec2a2ceb1bf3f5e90dc5fc07524e1f to your computer and use it in GitHub Desktop.
usePagination
This file contains hidden or 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 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} <{e.email}></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