Skip to content

Commit

Permalink
feat: add useBackgroundQuery and useReadQuery Suspense hooks (#10755
Browse files Browse the repository at this point in the history
)
  • Loading branch information
alessbell committed May 15, 2023
1 parent 032251f commit e3c676d
Show file tree
Hide file tree
Showing 13 changed files with 2,454 additions and 85 deletions.
5 changes: 5 additions & 0 deletions .changeset/seven-onions-burn.md
@@ -0,0 +1,5 @@
---
'@apollo/client': minor
---

Feature: adds `useBackgroundQuery` and `useReadQuery` hooks
2 changes: 2 additions & 0 deletions .prettierignore
Expand Up @@ -56,8 +56,10 @@ src/react/hooks/*
!src/react/hooks/internal
!src/react/hooks/useSuspenseCache.ts
!src/react/hooks/useSuspenseQuery.ts
!src/react/hooks/useBackgroundQuery.ts

## Allowed React hook tests
!src/react/hooks/__tests__/
src/react/hooks/__tests__/*
!src/react/hooks/__tests__/useSuspenseQuery.test.tsx
!src/react/hooks/__tests__/useBackgroundQuery.test.tsx
4 changes: 3 additions & 1 deletion .size-limit.cjs
@@ -1,7 +1,7 @@
const checks = [
{
path: "dist/apollo-client.min.cjs",
limit: "36.68kb"
limit: "36.84kb"
},
{
path: "dist/main.cjs",
Expand All @@ -19,6 +19,8 @@ const checks = [
"useMutation",
"useSubscription",
"useSuspenseQuery_experimental",
"useBackgroundQuery_experimental",
"useReadQuery_experimental",
"useFragment_experimental"
].map((name) => ({ path: "dist/react/index.js", import: `{ ${name} }` })),
].map((config) => ({
Expand Down
2 changes: 1 addition & 1 deletion config/bundlesize.ts
Expand Up @@ -3,7 +3,7 @@ import { join } from "path";
import { gzipSync } from "zlib";
import bytes from "bytes";

const gzipBundleByteLengthLimit = bytes("35.10KB");
const gzipBundleByteLengthLimit = bytes("35.25KB");
const minFile = join("dist", "apollo-client.min.cjs");
const minPath = join(__dirname, "..", minFile);
const gzipByteLen = gzipSync(readFileSync(minPath)).byteLength;
Expand Down
3 changes: 2 additions & 1 deletion config/jest.config.js
Expand Up @@ -29,7 +29,8 @@ const react17TestFileIgnoreList = [
ignoreTSFiles,
// For now, we only support useSuspenseQuery with React 18, so no need to test
// it with React 17
'src/react/hooks/__tests__/useSuspenseQuery.test.tsx'
'src/react/hooks/__tests__/useSuspenseQuery.test.tsx',
'src/react/hooks/__tests__/useBackgroundQuery.test.tsx'
]

const tsStandardConfig = {
Expand Down
6 changes: 6 additions & 0 deletions src/__tests__/__snapshots__/exports.ts.snap
Expand Up @@ -55,11 +55,13 @@ Array [
"throwServerError",
"toPromise",
"useApolloClient",
"useBackgroundQuery_experimental",
"useFragment_experimental",
"useLazyQuery",
"useMutation",
"useQuery",
"useReactiveVar",
"useReadQuery_experimental",
"useSubscription",
"useSuspenseQuery_experimental",
]
Expand Down Expand Up @@ -252,11 +254,13 @@ Array [
"parser",
"resetApolloContext",
"useApolloClient",
"useBackgroundQuery_experimental",
"useFragment_experimental",
"useLazyQuery",
"useMutation",
"useQuery",
"useReactiveVar",
"useReadQuery_experimental",
"useSubscription",
"useSuspenseQuery_experimental",
]
Expand Down Expand Up @@ -292,11 +296,13 @@ Array [
exports[`exports of public entry points @apollo/client/react/hooks 1`] = `
Array [
"useApolloClient",
"useBackgroundQuery_experimental",
"useFragment_experimental",
"useLazyQuery",
"useMutation",
"useQuery",
"useReactiveVar",
"useReadQuery_experimental",
"useSubscription",
"useSuspenseQuery_experimental",
]
Expand Down
Expand Up @@ -20,15 +20,16 @@ type FetchMoreOptions<TData> = Parameters<
ObservableQuery<TData>['fetchMore']
>[0];

interface QuerySubscriptionOptions {
interface QueryReferenceOptions {
onDispose?: () => void;
autoDisposeTimeoutMs?: number;
}

export class QuerySubscription<TData = unknown> {
export class QueryReference<TData = unknown> {
public result: ApolloQueryResult<TData>;
public readonly observable: ObservableQuery<TData>;

public version: 'main' | 'network' = 'main';
public promises: {
main: Promise<ApolloQueryResult<TData>>;
network?: Promise<ApolloQueryResult<TData>>;
Expand All @@ -45,7 +46,7 @@ export class QuerySubscription<TData = unknown> {

constructor(
observable: ObservableQuery<TData>,
options: QuerySubscriptionOptions = Object.create(null)
options: QueryReferenceOptions = Object.create(null)
) {
this.listen = this.listen.bind(this);
this.handleNext = this.handleNext.bind(this);
Expand Down Expand Up @@ -83,7 +84,7 @@ export class QuerySubscription<TData = unknown> {
}

// Start a timer that will automatically dispose of the query if the
// suspended resource does not use this subscription in the given time. This
// suspended resource does not use this queryRef in the given time. This
// helps prevent memory leaks when a component has unmounted before the
// query has finished loading.
this.autoDisposeTimeoutId = setTimeout(
Expand Down
16 changes: 8 additions & 8 deletions src/react/cache/SuspenseCache.ts
@@ -1,7 +1,7 @@
import { Trie } from '@wry/trie';
import type { ObservableQuery } from '../../core';
import { canUseWeakMap } from '../../utilities';
import { QuerySubscription } from './QuerySubscription';
import { QueryReference } from './QueryReference';

type CacheKey = any[];

Expand All @@ -25,29 +25,29 @@ export class SuspenseCache {
(cacheKey: CacheKey) => cacheKey
);

private subscriptions = new Map<CacheKey, QuerySubscription>();
private queryRefs = new Map<CacheKey, QueryReference>();
private options: SuspenseCacheOptions;

constructor(options: SuspenseCacheOptions = Object.create(null)) {
this.options = options;
}

getSubscription<TData = any>(
getQueryRef<TData = any>(
cacheKey: CacheKey,
createObservable: () => ObservableQuery<TData>
) {
const stableCacheKey = this.cacheKeys.lookupArray(cacheKey);

if (!this.subscriptions.has(stableCacheKey)) {
this.subscriptions.set(
if (!this.queryRefs.has(stableCacheKey)) {
this.queryRefs.set(
stableCacheKey,
new QuerySubscription(createObservable(), {
new QueryReference(createObservable(), {
autoDisposeTimeoutMs: this.options.autoDisposeTimeoutMs,
onDispose: () => this.subscriptions.delete(stableCacheKey),
onDispose: () => this.queryRefs.delete(stableCacheKey),
})
);
}

return this.subscriptions.get(stableCacheKey)! as QuerySubscription<TData>;
return this.queryRefs.get(stableCacheKey)! as QueryReference<TData>;
}
}

0 comments on commit e3c676d

Please sign in to comment.