Skip to content

Commit

Permalink
Hide queryRef in a Symbol in useBackgroundQuery return value (#11010)
Browse files Browse the repository at this point in the history
  • Loading branch information
alessbell authored Jun 26, 2023
1 parent 659539e commit 1051a9c
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 35 deletions.
5 changes: 5 additions & 0 deletions .changeset/smooth-clouds-sort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@apollo/client': patch
---

Hide queryRef in a Symbol in `useBackgroundQuery`s return value.
4 changes: 2 additions & 2 deletions .size-limit.cjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const checks = [
{
path: "dist/apollo-client.min.cjs",
limit: "37700"
limit: "37750"
},
{
path: "dist/main.cjs",
Expand All @@ -10,7 +10,7 @@ const checks = [
{
path: "dist/index.js",
import: "{ ApolloClient, InMemoryCache, HttpLink }",
limit: "33269"
limit: "33375"
},
...[
"ApolloProvider",
Expand Down
17 changes: 14 additions & 3 deletions src/react/cache/QueryReference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,31 @@ import { NetworkStatus, isNetworkRequestSettled } from '../../core';
import type { ObservableSubscription } from '../../utilities';
import { createFulfilledPromise, createRejectedPromise } from '../../utilities';
import type { CacheKey } from './types';
import type { useBackgroundQuery, useReadQuery } from '../hooks';

type Listener<TData> = (promise: Promise<ApolloQueryResult<TData>>) => void;

type FetchMoreOptions<TData> = Parameters<
ObservableQuery<TData>['fetchMore']
>[0];

interface QueryReferenceOptions {
export const QUERY_REFERENCE_SYMBOL: unique symbol = Symbol();
/**
* A `QueryReference` is an opaque object returned by {@link useBackgroundQuery}.
* A child component reading the `QueryReference` via {@link useReadQuery} will
* suspend until the promise resolves.
*/
export interface QueryReference<TData = unknown> {
[QUERY_REFERENCE_SYMBOL]: InternalQueryReference<TData>;
}

interface InternalQueryReferenceOptions {
key: CacheKey;
onDispose?: () => void;
autoDisposeTimeoutMs?: number;
}

export class QueryReference<TData = unknown> {
export class InternalQueryReference<TData = unknown> {
public result: ApolloQueryResult<TData>;
public readonly key: CacheKey;
public readonly observable: ObservableQuery<TData>;
Expand All @@ -41,7 +52,7 @@ export class QueryReference<TData = unknown> {

constructor(
observable: ObservableQuery<TData>,
options: QueryReferenceOptions
options: InternalQueryReferenceOptions
) {
this.listen = this.listen.bind(this);
this.handleNext = this.handleNext.bind(this);
Expand Down
8 changes: 4 additions & 4 deletions src/react/cache/SuspenseCache.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Trie } from '@wry/trie';
import type { ObservableQuery } from '../../core';
import { canUseWeakMap } from '../../utilities';
import { QueryReference } from './QueryReference';
import { InternalQueryReference } from './QueryReference';
import type { CacheKey } from './types';

interface SuspenseCacheOptions {
Expand All @@ -19,7 +19,7 @@ interface SuspenseCacheOptions {
}

export class SuspenseCache {
private queryRefs = new Trie<{ current?: QueryReference }>(canUseWeakMap);
private queryRefs = new Trie<{ current?: InternalQueryReference }>(canUseWeakMap);
private options: SuspenseCacheOptions;

constructor(options: SuspenseCacheOptions = Object.create(null)) {
Expand All @@ -33,7 +33,7 @@ export class SuspenseCache {
const ref = this.queryRefs.lookupArray(cacheKey);

if (!ref.current) {
ref.current = new QueryReference(createObservable(), {
ref.current = new InternalQueryReference(createObservable(), {
key: cacheKey,
autoDisposeTimeoutMs: this.options.autoDisposeTimeoutMs,
onDispose: () => {
Expand All @@ -42,6 +42,6 @@ export class SuspenseCache {
});
}

return ref.current as QueryReference<TData>;
return ref.current as InternalQueryReference<TData>;
}
}
21 changes: 11 additions & 10 deletions src/react/hooks/__tests__/useBackgroundQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
import { concatPagination, offsetLimitPagination } from '../../../utilities';
import { useBackgroundQuery, useReadQuery } from '../useBackgroundQuery';
import { ApolloProvider } from '../../context';
import { QUERY_REFERENCE_SYMBOL } from '../../cache/QueryReference';
import { SuspenseCache } from '../../cache';
import { InMemoryCache } from '../../../cache';
import {
Expand Down Expand Up @@ -617,7 +618,7 @@ describe('useBackgroundQuery', () => {

const [queryRef] = result.current;

const _result = await queryRef.promise;
const _result = await queryRef[QUERY_REFERENCE_SYMBOL].promise;

expect(_result).toEqual({
data: { hello: 'world 1' },
Expand Down Expand Up @@ -654,7 +655,7 @@ describe('useBackgroundQuery', () => {

const [queryRef] = result.current;

const _result = await queryRef.promise;
const _result = await queryRef[QUERY_REFERENCE_SYMBOL].promise;

await waitFor(() => {
expect(_result).toEqual({
Expand Down Expand Up @@ -739,7 +740,7 @@ describe('useBackgroundQuery', () => {

const [queryRef] = result.current;

const _result = await queryRef.promise;
const _result = await queryRef[QUERY_REFERENCE_SYMBOL].promise;

await waitFor(() => {
expect(_result).toMatchObject({
Expand Down Expand Up @@ -803,7 +804,7 @@ describe('useBackgroundQuery', () => {

const [queryRef] = result.current;

const _result = await queryRef.promise;
const _result = await queryRef[QUERY_REFERENCE_SYMBOL].promise;
const resultSet = new Set(_result.data.results);
const values = Array.from(resultSet).map((item) => item.value);

Expand Down Expand Up @@ -868,7 +869,7 @@ describe('useBackgroundQuery', () => {

const [queryRef] = result.current;

const _result = await queryRef.promise;
const _result = await queryRef[QUERY_REFERENCE_SYMBOL].promise;
const resultSet = new Set(_result.data.results);
const values = Array.from(resultSet).map((item) => item.value);

Expand Down Expand Up @@ -913,7 +914,7 @@ describe('useBackgroundQuery', () => {

const [queryRef] = result.current;

const _result = await queryRef.promise;
const _result = await queryRef[QUERY_REFERENCE_SYMBOL].promise;

expect(_result).toEqual({
data: { hello: 'from link' },
Expand Down Expand Up @@ -956,7 +957,7 @@ describe('useBackgroundQuery', () => {

const [queryRef] = result.current;

const _result = await queryRef.promise;
const _result = await queryRef[QUERY_REFERENCE_SYMBOL].promise;

expect(_result).toEqual({
data: { hello: 'from cache' },
Expand Down Expand Up @@ -1006,7 +1007,7 @@ describe('useBackgroundQuery', () => {

const [queryRef] = result.current;

const _result = await queryRef.promise;
const _result = await queryRef[QUERY_REFERENCE_SYMBOL].promise;

expect(_result).toEqual({
data: { foo: 'bar', hello: 'from link' },
Expand Down Expand Up @@ -1049,7 +1050,7 @@ describe('useBackgroundQuery', () => {

const [queryRef] = result.current;

const _result = await queryRef.promise;
const _result = await queryRef[QUERY_REFERENCE_SYMBOL].promise;

expect(_result).toEqual({
data: { hello: 'from link' },
Expand Down Expand Up @@ -1095,7 +1096,7 @@ describe('useBackgroundQuery', () => {

const [queryRef] = result.current;

const _result = await queryRef.promise;
const _result = await queryRef[QUERY_REFERENCE_SYMBOL].promise;

expect(_result).toEqual({
data: { hello: 'from link' },
Expand Down
29 changes: 16 additions & 13 deletions src/react/hooks/useBackgroundQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import type {
} from '../../core';
import { NetworkStatus } from '../../core';
import { useApolloClient } from './useApolloClient';
import type { QueryReference } from '../cache/QueryReference';
import {
QUERY_REFERENCE_SYMBOL,
type QueryReference,
} from '../cache/QueryReference';
import type { SuspenseQueryHookOptions, NoInfer } from '../types/types';
import { __use } from './internal';
import { useSuspenseCache } from './useSuspenseCache';
Expand Down Expand Up @@ -188,7 +191,7 @@ export function useBackgroundQuery<

return useMemo(() => {
return [
queryRef,
{ [QUERY_REFERENCE_SYMBOL]: queryRef },
{
fetchMore,
refetch,
Expand All @@ -199,41 +202,41 @@ export function useBackgroundQuery<

export function useReadQuery<TData>(queryRef: QueryReference<TData>) {
const [, forceUpdate] = useState(0);

const internalQueryRef = queryRef[QUERY_REFERENCE_SYMBOL];
invariant(
queryRef.promiseCache,
internalQueryRef.promiseCache,
'It appears that `useReadQuery` was used outside of `useBackgroundQuery`. ' +
'`useReadQuery` is only supported for use with `useBackgroundQuery`. ' +
'Please ensure you are passing the `queryRef` returned from `useBackgroundQuery`.'
);

const skipResult = useMemo(() => {
const error = toApolloError(queryRef.result);
const error = toApolloError(internalQueryRef.result);

return {
loading: false,
data: queryRef.result.data,
data: internalQueryRef.result.data,
networkStatus: error ? NetworkStatus.error : NetworkStatus.ready,
error,
};
}, [queryRef.result]);
}, [internalQueryRef.result]);

let promise = queryRef.promiseCache.get(queryRef.key);
let promise = internalQueryRef.promiseCache.get(internalQueryRef.key);

if (!promise) {
promise = queryRef.promise;
queryRef.promiseCache.set(queryRef.key, promise);
promise = internalQueryRef.promise;
internalQueryRef.promiseCache.set(internalQueryRef.key, promise);
}

useEffect(() => {
return queryRef.listen((promise) => {
queryRef.promiseCache!.set(queryRef.key, promise);
return internalQueryRef.listen((promise) => {
internalQueryRef.promiseCache!.set(internalQueryRef.key, promise);
forceUpdate((prevState) => prevState + 1);
});
}, [queryRef]);

const result =
queryRef.watchQueryOptions.fetchPolicy === 'standby'
internalQueryRef.watchQueryOptions.fetchPolicy === 'standby'
? skipResult
: __use(promise);

Expand Down
6 changes: 3 additions & 3 deletions src/react/hooks/useSuspenseQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import type {
} from '../types/types';
import { useDeepMemo, useStrictModeSafeCleanupEffect, __use } from './internal';
import { useSuspenseCache } from './useSuspenseCache';
import type { QueryReference } from '../cache/QueryReference';
import type { InternalQueryReference } from '../cache/QueryReference';
import { canonicalStringify } from '../../cache';

export interface UseSuspenseQueryResult<
Expand Down Expand Up @@ -296,8 +296,8 @@ export function toApolloError(result: ApolloQueryResult<any>) {
: result.error;
}

export function useTrackedQueryRefs(queryRef: QueryReference) {
const trackedQueryRefs = useRef(new Set<QueryReference>());
export function useTrackedQueryRefs(queryRef: InternalQueryReference) {
const trackedQueryRefs = useRef(new Set<InternalQueryReference>());

trackedQueryRefs.current.add(queryRef);

Expand Down

0 comments on commit 1051a9c

Please sign in to comment.