diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3d7219bf3f1..45d47f29beb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,9 @@
- Fix ObservableQuery.getCurrentResult() returning cached data with certain fetch policies.
[@brainkim](https://github.com/brainkim) in [#8718](https://github.com/apollographql/apollo-client/pull/8718)
+- Prevent `ssrMode`/`ssrForceFetchDelay` from causing queries to hang.
+ [@brainkim](https://github.com/brainkim) in [#8709](https://github.com/apollographql/apollo-client/pull/8709)
+
## Apollo Client 3.4.9
diff --git a/src/react/data/QueryData.ts b/src/react/data/QueryData.ts
index 71e05d0f718..1c736caa483 100644
--- a/src/react/data/QueryData.ts
+++ b/src/react/data/QueryData.ts
@@ -101,11 +101,7 @@ export class QueryData extends OperationData<
public afterExecute({ lazy = false }: { lazy?: boolean } = {}) {
this.isMounted = true;
const options = this.getOptions();
- if (
- this.currentObservable &&
- !this.ssrInitiated() &&
- !this.client.disableNetworkFetches
- ) {
+ if (this.currentObservable && !this.ssrInitiated()) {
this.startQuerySubscription();
}
diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx
index 6c0e03b625a..ed27fc947c2 100644
--- a/src/react/hooks/__tests__/useQuery.test.tsx
+++ b/src/react/hooks/__tests__/useQuery.test.tsx
@@ -557,6 +557,74 @@ describe('useQuery Hook', () => {
expect(result.current.loading).toBe(false);
expect(result.current.data).toEqual({ hello: 'from link' });
});
+
+ it('should use the cache when in ssrMode and fetchPolicy is `network-only`', async () => {
+ const query = gql`query { hello }`;
+ const link = mockSingleLink(
+ {
+ request: { query },
+ result: { data: { hello: 'from link' } },
+ },
+ );
+
+ const cache = new InMemoryCache();
+ cache.writeQuery({
+ query,
+ data: { hello: 'from cache' },
+ });
+
+ const client = new ApolloClient({ link, cache, ssrMode: true, });
+ const { result, waitForNextUpdate } = renderHook(
+ () => useQuery(query, { fetchPolicy: 'network-only' }),
+ {
+ wrapper: ({ children }) => (
+
+ {children}
+
+ ),
+ },
+ );
+
+ expect(result.current.loading).toBe(false);
+ expect(result.current.data).toEqual({ hello: 'from cache' });
+
+ await expect(waitForNextUpdate({ timeout: 20 }))
+ .rejects.toThrow('Timed out');
+ });
+
+ it('should not hang when ssrMode is true but the cache is not populated for some reason', async () => {
+ const query = gql`query { hello }`;
+ const link = mockSingleLink(
+ {
+ request: { query },
+ result: { data: { hello: 'from link' } },
+ },
+ );
+
+ const client = new ApolloClient({
+ link,
+ cache: new InMemoryCache(),
+ ssrMode: true,
+ });
+ const { result, waitForNextUpdate } = renderHook(
+ () => useQuery(query),
+ {
+ wrapper: ({ children }) => (
+
+ {children}
+
+ ),
+ },
+ );
+
+ expect(result.current.loading).toBe(true);
+ expect(result.current.data).toBe(undefined);
+
+ await waitForNextUpdate();
+
+ expect(result.current.loading).toBe(false);
+ expect(result.current.data).toEqual({ hello: 'from link' });
+ });
});
describe('polling', () => {
diff --git a/src/react/ssr/__tests__/useQuery.test.tsx b/src/react/ssr/__tests__/useQuery.test.tsx
index cbf86af997c..0e5aacb584b 100644
--- a/src/react/ssr/__tests__/useQuery.test.tsx
+++ b/src/react/ssr/__tests__/useQuery.test.tsx
@@ -6,7 +6,6 @@ import { ApolloClient } from '../../../core';
import { InMemoryCache } from '../../../cache';
import { ApolloProvider } from '../../context';
import { useApolloClient, useQuery } from '../../hooks';
-import { render, wait } from '@testing-library/react';
import { renderToStringWithData } from '..';
describe('useQuery Hook SSR', () => {
@@ -109,9 +108,7 @@ describe('useQuery Hook SSR', () => {
});
});
- it(
- 'should skip both SSR tree rendering and SSR component rendering if ' +
- '`ssr` option is `false` and `ssrMode` is `true`',
+ it('should skip both SSR tree rendering and SSR component rendering if `ssr` option is `false` and `ssrMode` is `true`',
async () => {
const link = mockSingleLink({
request: { query: CAR_QUERY },
@@ -136,6 +133,7 @@ describe('useQuery Hook SSR', () => {
break;
case 1: // FAIL; should not render a second time
default:
+ throw new Error("Duplicate render");
}
renderCount += 1;
@@ -148,22 +146,12 @@ describe('useQuery Hook SSR', () => {
);
- await renderToStringWithData(app).then(result => {
- expect(renderCount).toBe(1);
- expect(result).toEqual('');
- });
-
- renderCount = 0;
-
- render(
-
-
-
- );
-
- await wait(() => {
- expect(renderCount).toBe(1);
- });
+ const result = await renderToStringWithData(app);
+ expect(renderCount).toBe(1);
+ expect(result).toEqual('');
+ await new Promise((resolve) => setTimeout(resolve, 20));
+ expect(renderCount).toBe(1);
+ expect(result).toEqual('');
}
);