From 35e13e457e8050b3953fbf9a6700c4ea0e1def08 Mon Sep 17 00:00:00 2001 From: Chris Sauve Date: Thu, 27 Jun 2019 12:39:42 -0400 Subject: [PATCH 1/3] use-cache-in-ssr --- packages/react-graphql/src/hooks/query.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/react-graphql/src/hooks/query.ts b/packages/react-graphql/src/hooks/query.ts index e2d40b454c..24adba792f 100644 --- a/packages/react-graphql/src/hooks/query.ts +++ b/packages/react-graphql/src/hooks/query.ts @@ -44,6 +44,10 @@ export default function useQuery< const query = useGraphQLDocument(queryOrComponent); + const normalizedFetchPolicy = + typeof window === 'undefined' && fetchPolicy === 'network-only' + ? 'cache-first' + : fetchPolicy; const serializedVariables = variables && JSON.stringify(variables); const watchQueryOptions = useMemo | null>( () => { @@ -55,7 +59,7 @@ export default function useQuery< query, context, variables, - fetchPolicy, + fetchPolicy: normalizedFetchPolicy, errorPolicy, pollInterval, notifyOnNetworkStatusChange, @@ -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, From c00fa630f836f90cd1be3c87a1d0abd7e3106352 Mon Sep 17 00:00:00 2001 From: Chris Sauve Date: Thu, 27 Jun 2019 12:40:45 -0400 Subject: [PATCH 2/3] Also handle no-cache case --- packages/react-graphql/src/hooks/query.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-graphql/src/hooks/query.ts b/packages/react-graphql/src/hooks/query.ts index 24adba792f..d187ff3e29 100644 --- a/packages/react-graphql/src/hooks/query.ts +++ b/packages/react-graphql/src/hooks/query.ts @@ -38,7 +38,7 @@ export default function useQuery< } = options; const client = useApolloClient(overrideClient); - if (typeof window === 'undefined' && skip) { + if ((typeof window === 'undefined' && skip) || fetchPolicy === 'no-cache') { return createDefaultResult(client, variables); } From db6378b3576983bf6b4d21e3e1ad56efeeb75f55 Mon Sep 17 00:00:00 2001 From: Chris Sauve Date: Thu, 4 Jul 2019 17:04:48 -0400 Subject: [PATCH 3/3] Tests --- packages/react-graphql/src/hooks/query.ts | 4 +- .../src/hooks/tests/query-ssr.test.tsx | 82 +++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 packages/react-graphql/src/hooks/tests/query-ssr.test.tsx diff --git a/packages/react-graphql/src/hooks/query.ts b/packages/react-graphql/src/hooks/query.ts index d187ff3e29..d250af816d 100644 --- a/packages/react-graphql/src/hooks/query.ts +++ b/packages/react-graphql/src/hooks/query.ts @@ -38,8 +38,8 @@ export default function useQuery< } = options; const client = useApolloClient(overrideClient); - if ((typeof window === 'undefined' && skip) || fetchPolicy === 'no-cache') { - return createDefaultResult(client, variables); + if (typeof window === 'undefined' && (skip || fetchPolicy === 'no-cache')) { + return {...createDefaultResult(client, variables), loading: !skip}; } const query = useGraphQLDocument(queryOrComponent); diff --git a/packages/react-graphql/src/hooks/tests/query-ssr.test.tsx b/packages/react-graphql/src/hooks/tests/query-ssr.test.tsx new file mode 100644 index 0000000000..0efdaae9a1 --- /dev/null +++ b/packages/react-graphql/src/hooks/tests/query-ssr.test.tsx @@ -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 ?
loading
:
{JSON.stringify(data)}
; +} + +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( + + + , + { + 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 = ( + + + + ); + + 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'); + }); +});