😁
urqlで無限ローディングUIを実装する
urqlで無限ローディングなUIを実装する方法がググってもそのまま真似できそうなパターンがあまり出てこなかったので記録しておこうと思います。
基本方針としてはドキュメントに書いてあるとおりに従います。
前提条件
以下の記事で紹介している無限スクロールのための汎用hookを使います。
実装
リストの最後の要素が画面内に収まったときに次ページをロードする実装です。
ArticleList.tsx
const LIMIT = 30
const ArticleList: React.VFC = () => {
const [pageVariables, setPageVariables] = useState([
{
offset: 0,
limit: LIMIT,
},
])
const handleReachEnd = useCallback(() => {
setPageVariables((v) => {
const lastPageVariable = v.at(-1)
const offset = lastPageVariable
? lastPageVariable.offset + lastPageVariable.limit
: null
return offset ? [...v, { offset, limit: LIMIT }] : v
})
}, [])
const { setLastElement } = useInfiniteScroll(handleReachEnd)
return (
<Box display="flex" flexDirection="column" gap="20px">
{pageVariables.map((v, i) => (
<ArticleListPage
key={i}
offset={v.offset}
limit={v.limit}
setRef={
i === pageVariables.length - 1
? (ref) => {
setLastElement(ref)
}
: undefined
}
/>
))}
</Box>
)
}
export { ArticleList }
ArticleListPage.tsx
type Props = {
offset: number
limit: number
setRef?: (ref: HTMLDivElement | null) => void
}
const ArticleListPage: React.VFC<Props> = ({ offset, limit, setRef }) => {
const [{ data: articlesResponse, fetching }] = useQuery<
GetArticlesQuery,
GetArticleQueryVariables
>({
query: getArticlesQuery,
variables: {
offset,
limit,
},
})
return fetching ? (
<Box display="flex" justifyContent="center" paddingTop="20px">
<Spinner />
</Box>
) : (
<SimpleGrid columns={2} gap="20px">
{articlesResponse.length > 0 &&
articlesResponse.map((article) => (
<Box key={article.id} ref={setRef}>
<ArticleCard article={article} />
</Box>
))}
</SimpleGrid>
)
}
export { ArticleListPage }
Discussion