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 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() { 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 40f3a9cfe05..cbf86af997c 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,96 @@ 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>/); + expect(cache.extract()).toMatchSnapshot(); + }); + }); });