@epfl-si/react-graphql-paginated
Like @epfl-si/react-graphql-simple
, but with an extra helping of @tanstack/react-query
for useInfiniteGraphQLQuery
goodness.
- All bells and whistles of [
@tanstack/react-query
] are turned off by default — But you can turn them back on, if you want. - For now, only relay-style pagination is provided - Meaning that your GraphQL server must support it.
Provide a GraphQL context
The <QueryClientGraphQLProvider>
React component is a mix of @tanstack/react-query
's <QueryProvider>
and @epfl-si/react-graphql-simple
's <GraphQLProvider>
:
import { OIDCContext, useOpenIDConnectContext } from "@epfl-si/react-appauth";
import { QueryClientGraphQLProvider } from "@epfl-si/react-graphql-paginated";
function App() {
const oidcContextProps = { authServerUrl, ... }
return <OIDCContext { ...oidcContextProps }>
<QueryClientGraphQLProvider endpoint="/graphql" authentication={
{ bearer: () => useOpenIDConnectContext().accessToken }
}>
<MoreComponentsForYourApp/>
</QueryClientGraphQLProvider>
</OIDCContext>
}
Perform GraphQL requests from within the context
A <QueryClientGraphQLProvider>
component works just the same as a <GraphQLProvider>
component from @epfl-si/react-graphql-simple
; in particular, one can call useGraphQLRequest
from within it. Additionally, the children elements may call the useInfiniteGraphQLQuery
React hook, which is built around @tanstack/react-query
's useInfiniteQuery
. For example:
import * as React from "react";
import { gql } from 'graphql-request';
import { useInfiniteGraphQLQuery } from '@epfl-si/react-graphql-paginated';
type Item = { id : number, title : string, description : string };
export function InfiniteItemList() {
const { data,
error,
isFetching,
hasNextPage,
fetchNextPage,
isFetchingNextPage
} = useInfiniteGraphQLQuery<{ items: { nodes: Item[] } }>(gql`
query Items ($cursor : String) {
items(first: 10, after : $cursor) {
nodes {
id
title
description
}
pageInfo {
endCursor
hasNextPage
}
}
}`, relayStylePagination());
if (isFetching && !isFetchingNextPage) return <Throbber/>;
if (error) return <p>{error.toString()}</p>;
return <div><>{(data?.pages || []).map((page) => (
// Use React keys to prevent excessive DOM destruction / creation
// (which would also cause your page to scroll back up all the time):
<React.Fragment key={page.items.nodes[0]?.id}>
{page.items.nodes.map((item) =>
<p key={item.id}>{item.title}</p>)}
</React.Fragment>
))}</>
<button onclick={ () => fetchNextPage }>Moar</button>
</div>;
}
💡 Instead of (or in addition to) the clickable <button>
at the end, one could attach a react-intersection-observer
to a DOM element situated at the end of the list, so that fetchNextPage()
is called automatically as soon as said DOM element becomes visible within the browser viewport. This would deliver infinite scrolling for your useInfiniteGraphQLQuery
.