Closed paulgrieselhuber closed 4 years ago
There is a great way, but it it's a bit tricky to explain right now. Essentially, you use recursion to render pages. Each page has its own query, and if that page is cached it renders, if not a load button is rendered instead and recursion stops.
Here is an example, you can see it live at https://whimsy.art/art
import { ButtonSubmit, Heading, Scroll } from 'device-agnostic-ui';
import PropTypes from 'prop-types';
import React from 'react';
import { Header } from '../../components/Header';
import { LinkCardArtwork } from '../../components/LinkCardArtwork';
import { Meta } from '../../components/Meta';
import { PageLoader } from '../../components/PageLoader';
import {
CARD_ARTWORK_IMAGE_HEIGHT,
CARD_ARTWORK_IMAGE_WIDTH,
CARD_PAGINATION_LIMIT,
LOCALE,
PIXEL_DENSITY,
} from '../../config';
import { useWhimsyAPI } from '../../hooks/useWhimsyAPI';
const fragmentArtworkConnectionFields = /* GraphQL */ `
fragment queryArtworkConnectionFields on QueryArtworkConnection {
page(
cursor: $cursor
limit: ${CARD_PAGINATION_LIMIT}
ascending: false
) {
hasNextPage
cursorLast
edges {
node {
id
title
price {
format
asCurrency {
format(locale: "${LOCALE}")
}
}
sold
image {
srcWebp: url(
width: ${CARD_ARTWORK_IMAGE_WIDTH}
height: ${CARD_ARTWORK_IMAGE_HEIGHT}
devicePixelRatio: ${PIXEL_DENSITY}
format: WEBP
resourceHints: { preload: true }
)
srcFallback: url(
width: ${CARD_ARTWORK_IMAGE_WIDTH}
height: ${CARD_ARTWORK_IMAGE_HEIGHT}
devicePixelRatio: ${PIXEL_DENSITY}
format: JPG
)
}
}
}
}
}
`;
const queryPaginatedArtworks = /* GraphQL */ `
${fragmentArtworkConnectionFields}
query($cursor: ID!) {
artworks {
...queryArtworkConnectionFields
}
}
`;
const PaginatedArtworks = ({ page, loadedEdges = page.edges }) => {
const operation = React.useMemo(
() => ({
variables: { cursor: page.cursorLast },
query: queryPaginatedArtworks,
}),
[page.cursorLast]
);
const { load, loading, cacheValue: { data } = {} } = useWhimsyAPI({
loadOnReload: true,
operation,
});
return data ? (
<PaginatedArtworks
page={data.artworks.page}
loadedEdges={[...loadedEdges, ...data.artworks.page.edges]}
/>
) : (
<>
{loadedEdges.map(({ node: { id, title, price, sold, image } }) => (
<LinkCardArtwork
key={id}
artworkId={id}
title={title}
priceBitcoin={price.format}
priceCurrency={price.asCurrency.format}
sold={sold}
imageSrcWebp={image.srcWebp}
imageSrcFallback={image.srcFallback}
/>
))}
{page.hasNextPage && (
<ButtonSubmit onClick={load} loading={loading}>
More
</ButtonSubmit>
)}
</>
);
};
PaginatedArtworks.propTypes = {
page: PropTypes.shape({
cursorLast: PropTypes.string,
hasNextPage: PropTypes.bool.isRequired,
edges: PropTypes.array,
}).isRequired,
loadedEdges: PropTypes.array,
};
const queryArtPage = /* GraphQL */ `
${fragmentArtworkConnectionFields}
query($cursor: ID) {
artworks {
count
...queryArtworkConnectionFields
}
}
`;
const ArtPage = () => {
const operation = React.useMemo(
() => ({
query: queryArtPage,
}),
[]
);
const pageQueryStatus = useWhimsyAPI({
loadOnMount: true,
loadOnReload: true,
loadOnReset: true,
operation,
});
return (
<>
<Meta title="Art" description="All artworks." />
<PageLoader
graphqlOperationStatus={pageQueryStatus}
renderData={(data) => (
<>
<Header>
<Heading size={1}>
{data.artworks.count} artwork
{data.artworks.count === 1 ? '' : 's'}
</Heading>
</Header>
{!!data.artworks.page.edges.length && (
<Scroll>
<PaginatedArtworks page={data.artworks.page} />
</Scroll>
)}
</>
)}
/>
</>
);
};
export default ArtPage;
You can see another pagination example in production here (the reviews):
https://www.bookwell.com.au/venue/kis-hair/melbourne/3000#reviews
Fantastic, this gives me plenty to work with. Thanks!
Hello,
I am considering using this package for a decent-sized project. It appears to me that there is no great way to do pagination with this package, is that correct?
Thanks, Paul