Skip to content
This repository has been archived by the owner on Oct 1, 2024. It is now read-only.

Fix cache-less queries in SSR #770

Merged
merged 3 commits into from
Jul 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions packages/react-graphql/src/hooks/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@ export default function useQuery<
} = options;
const client = useApolloClient(overrideClient);

if (typeof window === 'undefined' && skip) {
return createDefaultResult(client, variables);
if (typeof window === 'undefined' && (skip || fetchPolicy === 'no-cache')) {
return {...createDefaultResult(client, variables), loading: !skip};
}

const query = useGraphQLDocument(queryOrComponent);

const normalizedFetchPolicy =
typeof window === 'undefined' && fetchPolicy === 'network-only'
? 'cache-first'
GoodForOneFare marked this conversation as resolved.
Show resolved Hide resolved
: fetchPolicy;
const serializedVariables = variables && JSON.stringify(variables);
const watchQueryOptions = useMemo<WatchQueryOptions<Variables> | null>(
() => {
Expand All @@ -55,7 +59,7 @@ export default function useQuery<
query,
context,
variables,
fetchPolicy,
fetchPolicy: normalizedFetchPolicy,
errorPolicy,
pollInterval,
notifyOnNetworkStatusChange,
Expand All @@ -67,7 +71,7 @@ export default function useQuery<
// eslint-disable-next-line react-hooks/exhaustive-deps
context && JSON.stringify(context),
serializedVariables,
fetchPolicy,
normalizedFetchPolicy,
errorPolicy,
pollInterval,
notifyOnNetworkStatusChange,
Expand Down
82 changes: 82 additions & 0 deletions packages/react-graphql/src/hooks/tests/query-ssr.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* @jest-environment node
*/

import React from 'react';
import {renderToString} from 'react-dom/server';
import gql from 'graphql-tag';
import {FetchPolicy} from 'apollo-client';
import {createGraphQLFactory} from '@shopify/graphql-testing';
import {extract} from '@shopify/react-effect/server';

import useQuery from '../query';
import {ApolloProvider} from '../../ApolloProvider';

const petQuery = gql`
query PetQuery {
pets {
name
}
}
`;

const createGraphQL = createGraphQLFactory();
const mockData = {
pets: [
{
__typename: 'Cat',
name: 'Garfield',
},
],
};

function MockQuery({fetchPolicy = 'network-only' as FetchPolicy}) {
const {data, loading} = useQuery(petQuery, {fetchPolicy});
return loading ? <div>loading</div> : <pre>{JSON.stringify(data)}</pre>;
}

describe('useQuery', () => {
it('does not loop infinitely when a query has network-only during SSR', async () => {
const graphQL = createGraphQL({PetQuery: mockData});
const afterEachSpy = jest.fn();

const extractPromise = extract(
<ApolloProvider client={graphQL.client}>
<MockQuery fetchPolicy="network-only" />
</ApolloProvider>,
{
afterEachPass: afterEachSpy,
},
);

await graphQL.resolveAll();
await extractPromise;

// One call for the first pass, another call after the GraphQL
// resolves
expect(afterEachSpy).toHaveBeenCalledTimes(2);
});

it('does not run a query with the no-cache fetch policy during SSR', async () => {
const graphQL = createGraphQL({PetQuery: mockData});
const afterEachSpy = jest.fn();
const element = (
<ApolloProvider client={graphQL.client}>
<MockQuery fetchPolicy="no-cache" />
</ApolloProvider>
);

const extractPromise = extract(element, {
afterEachPass: afterEachSpy,
});

await graphQL.resolveAll();
await extractPromise;

// One call for the first pass, which is the only one because there are
// no GraphQL queries to resolve.
expect(afterEachSpy).toHaveBeenCalledTimes(1);

expect(renderToString(element)).toContain('loading');
});
});