From 816a7b6c94e9ea89200be3e8fb6ab85275782c8e Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Wed, 21 Jun 2023 10:32:13 +0200 Subject: [PATCH 1/2] `QueryReference`: check for `resolve`/`reject` --- .changeset/little-schools-roll.md | 5 +++++ src/react/cache/QueryReference.ts | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 .changeset/little-schools-roll.md diff --git a/.changeset/little-schools-roll.md b/.changeset/little-schools-roll.md new file mode 100644 index 00000000000..71cd7ddd874 --- /dev/null +++ b/.changeset/little-schools-roll.md @@ -0,0 +1,5 @@ +--- +'@apollo/client': patch +--- + +Fix a bug in `QueryReference` where `this.resolve` or `this.reject` might be executed even if `undefined`. diff --git a/src/react/cache/QueryReference.ts b/src/react/cache/QueryReference.ts index 04f1a4be60d..7f42e4013d5 100644 --- a/src/react/cache/QueryReference.ts +++ b/src/react/cache/QueryReference.ts @@ -36,8 +36,8 @@ export class QueryReference { private initialized = false; private refetching = false; - private resolve: (result: ApolloQueryResult) => void; - private reject: (error: unknown) => void; + private resolve: ((result: ApolloQueryResult) => void) | undefined; + private reject: ((error: unknown) => void) | undefined; constructor( observable: ObservableQuery, @@ -157,7 +157,9 @@ export class QueryReference { this.initialized = true; this.refetching = false; this.result = result; - this.resolve(result); + if (this.resolve) { + this.resolve(result); + } return; } @@ -182,7 +184,9 @@ export class QueryReference { if (!this.initialized || this.refetching) { this.initialized = true; this.refetching = false; - this.reject(error); + if (this.reject) { + this.reject(error); + } return; } From fcda4a93190d4232ec75aa3142d8f93e91c05c7d Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 23 Jun 2023 10:08:54 -0600 Subject: [PATCH 2/2] Add test for checking bug when refetching after data is in cache --- .../hooks/__tests__/useSuspenseQuery.test.tsx | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/react/hooks/__tests__/useSuspenseQuery.test.tsx b/src/react/hooks/__tests__/useSuspenseQuery.test.tsx index 96504d9d4d2..b5c3b738878 100644 --- a/src/react/hooks/__tests__/useSuspenseQuery.test.tsx +++ b/src/react/hooks/__tests__/useSuspenseQuery.test.tsx @@ -4408,6 +4408,55 @@ describe('useSuspenseQuery', () => { ]); }); + it('suspends when refetching after returning cached data for the initial fetch', async () => { + const { query, mocks } = useSimpleQueryCase(); + + const cache = new InMemoryCache(); + + cache.writeQuery({ + query, + data: { greeting: 'hello from cache' }, + }); + + const { result, renders } = renderSuspenseHook( + () => useSuspenseQuery(query), + { cache, mocks } + ); + + expect(result.current).toMatchObject({ + data: { greeting: 'hello from cache' }, + networkStatus: NetworkStatus.ready, + error: undefined, + }); + + act(() => { + result.current.refetch(); + }); + + await waitFor(() => { + expect(result.current).toMatchObject({ + data: { greeting: 'Hello' }, + networkStatus: NetworkStatus.ready, + error: undefined, + }); + }); + + expect(renders.count).toBe(3); + expect(renders.suspenseCount).toBe(1); + expect(renders.frames).toMatchObject([ + { + data: { greeting: 'hello from cache' }, + networkStatus: NetworkStatus.ready, + error: undefined, + }, + { + data: { greeting: 'Hello' }, + networkStatus: NetworkStatus.ready, + error: undefined, + }, + ]); + }); + it('properly uses `updateQuery` when calling `fetchMore`', async () => { const { data, query, link } = usePaginatedCase();