Apollo Query Result
Proof of concept implementation of Suspense for Data Fetching for Apollo.
WARNING! This is not a real package (yet)!
Implementation Details
Check out the useQueryResource.
useObservableQuery
First, we assign a unique ID to every query. By default, it is an operation name, but it can be configured explicitly.
Then, we create an ObservableQuery
and cache it in a Suspense Cache.
Every ID corresponds to exactly one ObservableQuery
.
const observableQuert = useObservableQuery(document, { variables });
useObservableQueryState
Next, we subscribe to ObservableQuery
updates using new useSyncExternalStore API.
Similar to the standard useQuery
.
const { loading, data, networkError, graphQLErrors } = useObservableQueryState(observableQuery);
settleObservableQuery
To suspend ObservableQuery
we have a helper that suspends query while loading
is true.
It also uses Suspense Cache to maintain a map
between ObservableQuery
and a suspension `Promises.
settleObservableQuery(observableQuery); // Suspends!
useQueryResource
Finally, we wrap everything together into a QueryResource.
const resource = useQueryResource(document, { variables });
resource.read(); // Suspends!
// You can also work with data as usual
resource.isLoading();
resource.error();
Example
import { gql } from "@apollo/client";
import { useQueryResource } from "@hired/apollo-query-resource";
const GetPostQuery = gql`
query GetPost($postId: Int!) {
post(id: $postId) {
id
title
body
}
}
`;
interface GetPostResult {
post: {
id: number;
title: string;
body: string;
}
}
interface interface GetPostVariables {
postId: number;
}
export const Post({ postId }: { postId: number }) {
const resource = useQueryResource<GetPostResult, GetPostVariables>(GetPostQuery, { variables: { postId } })
// No errors, no loading, just data!
const { post: { title, body }} = resource.read(); // Suspends!
return (
<>
<h1>{title}</h1>
<p>{body}</p>
<>
);
}
Requirements
Currently only works with React 18 experimental
.