From 854e77280b08cf166767178c056f64b9e8cde8b4 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 13 Apr 2021 15:16:55 -0400 Subject: [PATCH 1/4] Add failing test of reading cache data immediately during SSR. --- src/react/ssr/__tests__/useQuery.test.tsx | 93 ++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/src/react/ssr/__tests__/useQuery.test.tsx b/src/react/ssr/__tests__/useQuery.test.tsx index 40f3a9cfe05..d593d7e4f91 100644 --- a/src/react/ssr/__tests__/useQuery.test.tsx +++ b/src/react/ssr/__tests__/useQuery.test.tsx @@ -5,7 +5,7 @@ import { MockedProvider, mockSingleLink } from '../../../testing'; import { ApolloClient } from '../../../core'; import { InMemoryCache } from '../../../cache'; import { ApolloProvider } from '../../context'; -import { useQuery } from '../../hooks'; +import { useApolloClient, useQuery } from '../../hooks'; import { render, wait } from '@testing-library/react'; import { renderToStringWithData } from '..'; @@ -195,4 +195,95 @@ describe('useQuery Hook SSR', () => { expect(result).toBe(''); }); }); + + it('should return data written previously to cache during SSR pass if using cache-only fetchPolicy', async () => { + const cache = new InMemoryCache({ + typePolicies: { + Order: { + keyFields: ["selection"], + }, + }, + }); + + const query = gql` + query GetSearchResults { + getSearchResults @client { + locale + order { + selection + } + pagination { + pageLimit + } + results { + id + text + } + } + } + `; + + const initialData = { + getSearchResults: { + __typename: 'SearchResults', + locale: 'en-US', + order: { + __typename: 'Order', + selection: 'RELEVANCE', + }, + pagination: { + pageLimit: 3, + }, + results: [ + { __typename: "SearchResult", id: 1, text: "hi" }, + { __typename: "SearchResult", id: 2, text: "hello" }, + { __typename: "SearchResult", id: 3, text: "hey" }, + ], + }, + }; + + const spy = jest.fn(); + + const Component = () => { + useApolloClient().writeQuery({ query, data: initialData });; + + const { loading, data } = useQuery(query, { + fetchPolicy: 'cache-only', + }); + + spy(loading); + + if (!loading) { + expect(data).toEqual(initialData); + + const { + getSearchResults: { + pagination: { + pageLimit, + }, + }, + } = data; + return ( +
+ {pageLimit} +
+ ); + } + return null; + }; + + const app = ( + + + + ); + + return renderToStringWithData(app).then(markup => { + expect(spy).toHaveBeenNthCalledWith(1, false); + expect(markup).toMatch(/3<\/div>/); + }); + }); }); From 8381b4d4a92dc94c74f41fb5f1be0af4affded31 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 13 Apr 2021 16:13:42 -0400 Subject: [PATCH 2/4] Allow SSR queries to return available cache data immediately. --- src/react/data/QueryData.ts | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/react/data/QueryData.ts b/src/react/data/QueryData.ts index 1b8ef175b9a..33c48ebc7c1 100644 --- a/src/react/data/QueryData.ts +++ b/src/react/data/QueryData.ts @@ -175,20 +175,13 @@ export class QueryData extends OperationData< return ssrLoading; } - let result; if (this.ssrInitiated()) { - if (skip) { - result = this.getQueryResult(); - } else { - result = - this.context.renderPromises!.addQueryPromise( - this, - this.getQueryResult - ) || ssrLoading; - }; + const result = this.getQueryResult() || ssrLoading; + if (result.loading && !skip) { + this.context.renderPromises!.addQueryPromise(this, () => null); + } + return result; } - - return result; } private prepareObservableQueryOptions() { From caead39f792defa4ac0b6c6b090a651ca51311a1 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 13 Apr 2021 16:52:20 -0400 Subject: [PATCH 3/4] Add inline snapshot test of SSR cache write. --- .../__snapshots__/useQuery.test.tsx.snap | 49 +++++++++++++++++++ src/react/ssr/__tests__/useQuery.test.tsx | 1 + 2 files changed, 50 insertions(+) create mode 100644 src/react/ssr/__tests__/__snapshots__/useQuery.test.tsx.snap diff --git a/src/react/ssr/__tests__/__snapshots__/useQuery.test.tsx.snap b/src/react/ssr/__tests__/__snapshots__/useQuery.test.tsx.snap new file mode 100644 index 00000000000..5403e168e7c --- /dev/null +++ b/src/react/ssr/__tests__/__snapshots__/useQuery.test.tsx.snap @@ -0,0 +1,49 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`useQuery Hook SSR should return data written previously to cache during SSR pass if using cache-only fetchPolicy 1`] = ` +Object { + "Order:{\\"selection\\":\\"RELEVANCE\\"}": Object { + "__typename": "Order", + "selection": "RELEVANCE", + }, + "ROOT_QUERY": Object { + "__typename": "Query", + "getSearchResults": Object { + "__typename": "SearchResults", + "locale": "en-US", + "order": Object { + "__ref": "Order:{\\"selection\\":\\"RELEVANCE\\"}", + }, + "pagination": Object { + "pageLimit": 3, + }, + "results": Array [ + Object { + "__ref": "SearchResult:1", + }, + Object { + "__ref": "SearchResult:2", + }, + Object { + "__ref": "SearchResult:3", + }, + ], + }, + }, + "SearchResult:1": Object { + "__typename": "SearchResult", + "id": 1, + "text": "hi", + }, + "SearchResult:2": Object { + "__typename": "SearchResult", + "id": 2, + "text": "hello", + }, + "SearchResult:3": Object { + "__typename": "SearchResult", + "id": 3, + "text": "hey", + }, +} +`; diff --git a/src/react/ssr/__tests__/useQuery.test.tsx b/src/react/ssr/__tests__/useQuery.test.tsx index d593d7e4f91..cbf86af997c 100644 --- a/src/react/ssr/__tests__/useQuery.test.tsx +++ b/src/react/ssr/__tests__/useQuery.test.tsx @@ -284,6 +284,7 @@ describe('useQuery Hook SSR', () => { return renderToStringWithData(app).then(markup => { expect(spy).toHaveBeenNthCalledWith(1, false); expect(markup).toMatch(/3<\/div>/); + expect(cache.extract()).toMatchSnapshot(); }); }); }); From 0ce80a8afc215c02a3fcdd27ada75e3ec9bad2e9 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 13 Apr 2021 17:12:35 -0400 Subject: [PATCH 4/4] Mention PR #7983 in CHANGELOG.md. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16cb3da9e34..1f620b526b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ - Increment `queryInfo.lastRequestId` only when making a network request through the `ApolloLink` chain, rather than every time `fetchQueryByPolicy` is called.
[@dannycochran](https://github.com/dannycochran) in [#7956](https://github.com/apollographql/apollo-client/pull/7956) +- During server-side rendering, allow initial `useQuery` calls to return final `{ loading: false, data }` results when the cache already contains the necessary data.
+ [@benjamn](https://github.com/benjamn) in [#7983](https://github.com/apollographql/apollo-client/pull/7983) + ## Apollo Client 3.3.14 ### Improvements