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();
+ });
+ });
});