diff --git a/packages/react-relay/relay-hooks/EntryPointTypes.flow.js b/packages/react-relay/relay-hooks/EntryPointTypes.flow.js index b9e1b667b8ebb..55de46b6887fe 100644 --- a/packages/react-relay/relay-hooks/EntryPointTypes.flow.js +++ b/packages/react-relay/relay-hooks/EntryPointTypes.flow.js @@ -45,12 +45,15 @@ export type LoadQueryOptions = { +__nameForWarning?: ?string, }; -// Note: the phantom type parameter here helps ensures that the -// $Parameters.js value matches the type param provided to preloadQuery. -// eslint-disable-next-line no-unused-vars export type PreloadableConcreteRequest = { kind: 'PreloadableConcreteRequest', params: RequestParameters, + // Note: the phantom type parameter here helps ensures that the + // $Parameters.js value matches the type param provided to preloadQuery. + // We also need to add usage of this generic here, + // becuase not using the generic in the definition makes it + // unconstrained in the call to a function that accepts PreloadableConcreteRequest + __phantom__?: ?TQuery, }; export type EnvironmentProviderOptions = {+[string]: mixed, ...}; diff --git a/packages/react-relay/relay-hooks/__tests__/loadQuery-source-behavior-test.js b/packages/react-relay/relay-hooks/__tests__/loadQuery-source-behavior-test.js index b2f7762daf24b..60e1ebacb9b73 100644 --- a/packages/react-relay/relay-hooks/__tests__/loadQuery-source-behavior-test.js +++ b/packages/react-relay/relay-hooks/__tests__/loadQuery-source-behavior-test.js @@ -15,7 +15,8 @@ import type { LoadQueryOptions, PreloadableConcreteRequest, } from '../EntryPointTypes.flow'; -import type {GraphQLTaggedNode, OperationType} from 'relay-runtime'; +import type {loadQuerySourceBehaviorTestQuery} from './__generated__/loadQuerySourceBehaviorTestQuery.graphql'; +import type {OperationType, Query} from 'relay-runtime'; import type {GraphQLResponse} from 'relay-runtime/network/RelayNetworkTypes'; const {loadQuery} = require('../loadQuery'); @@ -43,10 +44,11 @@ const query = graphql` } `; -const preloadableConcreteRequest = { - kind: 'PreloadableConcreteRequest', - params: query.params, -}; +const preloadableConcreteRequest: PreloadableConcreteRequest = + { + kind: 'PreloadableConcreteRequest', + params: query.params, + }; const response = { data: { @@ -148,11 +150,7 @@ beforeEach(() => { }); writeDataToStore = () => { - loadQuery<$FlowFixMe, _>( - environment, - preloadableConcreteRequest, - variables, - ); + loadQuery(environment, preloadableConcreteRequest, variables); sink.next(response); sink.complete(); PreloadableQueryRegistry.set(ID, query); @@ -163,12 +161,14 @@ beforeEach(() => { PreloadableQueryRegistry.clear(); }; - callLoadQuery = ( - queryAstOrRequest: GraphQLTaggedNode | PreloadableConcreteRequest, + callLoadQuery = ( + queryAstOrRequest: + | Query + | PreloadableConcreteRequest, options?: LoadQueryOptions, // $FlowFixMe[missing-local-annot] ) => { - const loadedQuery = loadQuery<$FlowFixMe, _>( + const loadedQuery = loadQuery( environment, queryAstOrRequest, variables, @@ -425,7 +425,7 @@ describe('when passed a PreloadableConcreteRequest', () => { // calls to load will get disposed // Start initial load of query - const queryRef1 = loadQuery<$FlowFixMe, _>( + const queryRef1 = loadQuery( environment, preloadableConcreteRequest, variables, @@ -446,7 +446,7 @@ describe('when passed a PreloadableConcreteRequest', () => { expect(environment.executeWithSource).toBeCalledTimes(1); // Start second load of query - const queryRef2 = loadQuery<$FlowFixMe, _>( + const queryRef2 = loadQuery( environment, preloadableConcreteRequest, variables, @@ -487,7 +487,7 @@ describe('when passed a PreloadableConcreteRequest', () => { describe('when passed a query AST', () => { it('should pass network responses onto source', () => { - callLoadQuery(query); + callLoadQuery(query); expect(next).not.toHaveBeenCalled(); sink.next(response); @@ -495,7 +495,7 @@ describe('when passed a query AST', () => { }); it('should pass network errors onto source', () => { - callLoadQuery(query); + callLoadQuery(query); expect(error).not.toHaveBeenCalled(); sink.error(networkError); @@ -504,14 +504,14 @@ describe('when passed a query AST', () => { describe('when dispose is called before the network response is available', () => { it('should not pass network responses onto source', () => { - const {dispose} = callLoadQuery(query); + const {dispose} = callLoadQuery(query); dispose(); sink.next(response); expect(next).not.toHaveBeenCalled(); }); it('should not pass network errors onto source', done => { - const {dispose} = callLoadQuery(query); + const {dispose} = callLoadQuery(query); dispose(); diff --git a/packages/react-relay/relay-hooks/__tests__/loadQuery-store-behavior-test.js b/packages/react-relay/relay-hooks/__tests__/loadQuery-store-behavior-test.js index 977be235ff865..c8e23c05074f1 100644 --- a/packages/react-relay/relay-hooks/__tests__/loadQuery-store-behavior-test.js +++ b/packages/react-relay/relay-hooks/__tests__/loadQuery-store-behavior-test.js @@ -19,7 +19,9 @@ import type { CacheConfig, Variables, } from '../../../relay-runtime/util/RelayRuntimeTypes'; +import type {PreloadableConcreteRequest} from '../EntryPointTypes.flow'; import type { + loadQueryStoreBehaviorTestQuery, loadQueryStoreBehaviorTestQuery$data, loadQueryStoreBehaviorTestQuery$variables, } from './__generated__/loadQueryStoreBehaviorTestQuery.graphql'; @@ -57,10 +59,11 @@ const query = graphql` const ID = '12345'; (query.params: $FlowFixMe).id = ID; -const preloadableConcreteRequest = { - kind: 'PreloadableConcreteRequest', - params: query.params, -}; +const preloadableConcreteRequest: PreloadableConcreteRequest = + { + kind: 'PreloadableConcreteRequest', + params: query.params, + }; const response: GraphQLSingularResponse = { data: { @@ -130,11 +133,7 @@ beforeEach(() => { .mockImplementation(() => resolvedModule); writeDataToStore = () => { - loadQuery( - environment, - preloadableConcreteRequest, - variables, - ); + loadQuery(environment, preloadableConcreteRequest, variables); sink.next(response); sink.complete(); PreloadableQueryRegistry.set(ID, query); @@ -157,11 +156,7 @@ describe('when passed a PreloadableConcreteRequest', () => { }); it('should write the data to the store after the query AST and network response are available', () => { expect(store.check(operation).status).toBe('missing'); - loadQuery( - environment, - preloadableConcreteRequest, - variables, - ); + loadQuery(environment, preloadableConcreteRequest, variables); expect(fetch).toHaveBeenCalled(); expect(store.check(operation).status).toBe('missing'); PreloadableQueryRegistry.set(ID, query); @@ -172,11 +167,7 @@ describe('when passed a PreloadableConcreteRequest', () => { it('should write the data to the store after the network response and query AST are available', () => { expect(store.check(operation).status).toBe('missing'); - loadQuery( - environment, - preloadableConcreteRequest, - variables, - ); + loadQuery(environment, preloadableConcreteRequest, variables); expect(store.check(operation).status).toBe('missing'); sink.next(response); expect(store.check(operation).status).toBe('missing'); @@ -186,7 +177,7 @@ describe('when passed a PreloadableConcreteRequest', () => { it('should not write the data to the store if dispose is called before the query AST and network response are available', () => { expect(store.check(operation).status).toBe('missing'); - const {dispose} = loadQuery( + const {dispose} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -200,7 +191,7 @@ describe('when passed a PreloadableConcreteRequest', () => { it('should not write the data to the store if dispose is called before the network response and query AST are available', () => { expect(store.check(operation).status).toBe('missing'); - const {dispose} = loadQuery( + const {dispose} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -214,7 +205,7 @@ describe('when passed a PreloadableConcreteRequest', () => { it('should not write the data to the store if dispose is called after the query AST is available, but before the network response is available', () => { expect(store.check(operation).status).toBe('missing'); - const {dispose} = loadQuery( + const {dispose} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -228,7 +219,7 @@ describe('when passed a PreloadableConcreteRequest', () => { it('should not write the data to the store if dispose is called after the network response is available, but before the query AST is available', () => { expect(store.check(operation).status).toBe('missing'); - const {dispose} = loadQuery( + const {dispose} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -244,18 +235,14 @@ describe('when passed a PreloadableConcreteRequest', () => { describe('when the query AST is available synchronously', () => { it('should write data to the store when the network response is available', () => { expect(store.check(operation).status).toBe('missing'); - loadQuery( - environment, - preloadableConcreteRequest, - variables, - ); + loadQuery(environment, preloadableConcreteRequest, variables); sink.next(response); expect(store.check(operation).status).toBe('available'); }); it('should not write data to the store if dispose is called before the network response is available', () => { expect(store.check(operation).status).toBe('missing'); - const {dispose} = loadQuery( + const {dispose} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -271,14 +258,9 @@ describe('when passed a PreloadableConcreteRequest', () => { beforeEach(() => writeDataToStore()); describe('when the query AST is available synchronously', () => { it('should write updated data to the store when the network response is available', () => { - loadQuery( - environment, - preloadableConcreteRequest, - variables, - { - fetchPolicy: 'network-only', - }, - ); + loadQuery(environment, preloadableConcreteRequest, variables, { + fetchPolicy: 'network-only', + }); expect( (store.lookup(operation.fragment): $FlowFixMe)?.data?.node?.name, @@ -290,7 +272,7 @@ describe('when passed a PreloadableConcreteRequest', () => { }); it('should not write updated data to the store if dispose is called before the network response is available', () => { - const {dispose} = loadQuery( + const {dispose} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -311,14 +293,9 @@ describe('when passed a PreloadableConcreteRequest', () => { resolvedModule = undefined; }); it('should write updated data to the store when the network response and query AST are available', () => { - loadQuery( - environment, - preloadableConcreteRequest, - variables, - { - fetchPolicy: 'network-only', - }, - ); + loadQuery(environment, preloadableConcreteRequest, variables, { + fetchPolicy: 'network-only', + }); expect( (store.lookup(operation.fragment): $FlowFixMe)?.data?.node?.name, @@ -334,14 +311,9 @@ describe('when passed a PreloadableConcreteRequest', () => { ).toEqual('Mark'); }); it('should write updated data to the store when the query AST and network response are available', () => { - loadQuery( - environment, - preloadableConcreteRequest, - variables, - { - fetchPolicy: 'network-only', - }, - ); + loadQuery(environment, preloadableConcreteRequest, variables, { + fetchPolicy: 'network-only', + }); expect( (store.lookup(operation.fragment): $FlowFixMe)?.data?.node?.name, @@ -358,7 +330,7 @@ describe('when passed a PreloadableConcreteRequest', () => { }); it('should not write updated data to the store if dispose is called before the network response and query AST are available', () => { - const {dispose} = loadQuery( + const {dispose} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -379,7 +351,7 @@ describe('when passed a PreloadableConcreteRequest', () => { }); it('should not write updated data to the store if dispose is called before the query AST and network response are available', () => { - const {dispose} = loadQuery( + const {dispose} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -400,7 +372,7 @@ describe('when passed a PreloadableConcreteRequest', () => { }); it('should not write updated data to the store if dispose is called after the query AST is available and before the network response is available', () => { - const {dispose} = loadQuery( + const {dispose} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -424,7 +396,7 @@ describe('when passed a PreloadableConcreteRequest', () => { }); it('should not write updated data to the store if dispose is called after ·the network repsonse is available and before the query AST is available', () => { - const {dispose} = loadQuery( + const {dispose} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -454,14 +426,14 @@ describe('when passed a query AST', () => { describe('when data is unavailable in the store', () => { it('should write data to the store when the network response is available', () => { expect(store.check(operation).status).toBe('missing'); - loadQuery(environment, query, variables); + loadQuery(environment, query, variables); sink.next(response); expect(store.check(operation).status).toBe('available'); }); it('should not write data to the store if dispose is called before the network response is available', () => { expect(store.check(operation).status).toBe('missing'); - const {dispose} = loadQuery(environment, query, variables); + const {dispose} = loadQuery(environment, query, variables); dispose(); sink.next(response); expect(store.check(operation).status).toBe('missing'); @@ -470,7 +442,7 @@ describe('when passed a query AST', () => { describe("when data is available in the store, but the fetch policy is 'network-only'", () => { beforeEach(() => writeDataToStore()); it('should write updated data to the store when the network response is available', () => { - loadQuery(environment, query, variables, { + loadQuery(environment, query, variables, { fetchPolicy: 'network-only', }); @@ -484,14 +456,9 @@ describe('when passed a query AST', () => { }); it('should not write updated data to the store if dispose is called before the network response is available', () => { - const {dispose} = loadQuery( - environment, - query, - variables, - { - fetchPolicy: 'network-only', - }, - ); + const {dispose} = loadQuery(environment, query, variables, { + fetchPolicy: 'network-only', + }); dispose(); sink.next(updatedResponse); diff --git a/packages/react-relay/relay-hooks/__tests__/loadQuery-test.js b/packages/react-relay/relay-hooks/__tests__/loadQuery-test.js index 08e6d66e31e78..13deae79e9092 100644 --- a/packages/react-relay/relay-hooks/__tests__/loadQuery-test.js +++ b/packages/react-relay/relay-hooks/__tests__/loadQuery-test.js @@ -10,20 +10,20 @@ */ 'use strict'; +import type {PreloadableConcreteRequest} from '../EntryPointTypes.flow'; import type { - LogRequestInfoFunction, - UploadableMap, -} from '../../../relay-runtime/network/RelayNetworkTypes'; -import type {RequestParameters} from '../../../relay-runtime/util/RelayConcreteNode'; -import type { - CacheConfig, - Variables, -} from '../../../relay-runtime/util/RelayRuntimeTypes'; -import type { + loadQueryTestQuery, loadQueryTestQuery$data, loadQueryTestQuery$variables, } from './__generated__/loadQueryTestQuery.graphql'; -import type {OperationType, Query} from 'relay-runtime/util/RelayRuntimeTypes'; +import type { + CacheConfig, + LogRequestInfoFunction, + Query, + RequestParameters, + UploadableMap, + Variables, +} from 'relay-runtime'; const {loadQuery, useTrackLoadQueryInRender} = require('../loadQuery'); // Need React require for OSS build @@ -60,10 +60,11 @@ describe('loadQuery', () => { (query.params: $FlowFixMe).id = ID; (query.params: $FlowFixMe).cacheID = ID; - const preloadableConcreteRequest = { - kind: 'PreloadableConcreteRequest', - params: query.params, - }; + const preloadableConcreteRequest: PreloadableConcreteRequest = + { + kind: 'PreloadableConcreteRequest', + params: query.params, + }; const response = { data: { @@ -189,29 +190,21 @@ describe('loadQuery', () => { describe('when passed a PreloadableConcreteRequest', () => { it('checks whether the query ast is available synchronously', () => { - loadQuery( - environment, - preloadableConcreteRequest, - variables, - ); + loadQuery(environment, preloadableConcreteRequest, variables); // $FlowFixMe[method-unbinding] added when improving typing for this parameters expect(PreloadableQueryRegistry.get).toHaveBeenCalled(); }); describe('when the query AST is available synchronously', () => { it('synchronously checks whether the query can be fulfilled by the store', () => { - loadQuery( - environment, - preloadableConcreteRequest, - variables, - ); + loadQuery(environment, preloadableConcreteRequest, variables); // $FlowFixMe[method-unbinding] added when improving typing for this parameters expect(environment.check).toHaveBeenCalled(); }); describe("with fetchPolicy === 'store-or-network'", () => { it('should not call fetch if the query can be fulfilled by the store', () => { - const {source} = loadQuery( + const {source} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -233,7 +226,7 @@ describe('loadQuery', () => { mockAvailability = {status: 'missing'}; }); it('makes a network request', done => { - const {source} = loadQuery( + const {source} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -275,7 +268,7 @@ describe('loadQuery', () => { }); it('should mark failed network requests', () => { - const preloadedQuery = loadQuery( + const preloadedQuery = loadQuery( environment, preloadableConcreteRequest, variables, @@ -294,7 +287,7 @@ describe('loadQuery', () => { it('calling dispose unsubscribes from executeWithSource', () => { // This ensures that no data is written to the store - const preloadedQuery = loadQuery( + const preloadedQuery = loadQuery( environment, preloadableConcreteRequest, variables, @@ -337,7 +330,7 @@ describe('loadQuery', () => { it('calling dispose unsubscribes from the network request', () => { // This ensures that live queries stop issuing network requests - const preloadedQuery = loadQuery( + const preloadedQuery = loadQuery( environment, preloadableConcreteRequest, variables, @@ -357,7 +350,7 @@ describe('loadQuery', () => { describe("with fetchPolicy === 'store-only'", () => { it('should not call fetch if the query can be fulfilled by the store', () => { - const {source} = loadQuery( + const {source} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -376,7 +369,7 @@ describe('loadQuery', () => { it('should not call fetch if the query cannot be fulfilled by the store', () => { mockAvailability = {status: 'missing'}; - const {source} = loadQuery( + const {source} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -394,7 +387,7 @@ describe('loadQuery', () => { }); it('calling dispose releases the query', () => { - const preloadedQuery = loadQuery( + const preloadedQuery = loadQuery( environment, preloadableConcreteRequest, variables, @@ -413,7 +406,7 @@ describe('loadQuery', () => { resolvedModule = null; }); it('should make a network request', done => { - const {source} = loadQuery( + const {source} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -456,7 +449,7 @@ describe('loadQuery', () => { expect(nextCallback).toHaveBeenCalledWith(response); }); it('should mark failed network requests', () => { - const preloadedQuery = loadQuery( + const preloadedQuery = loadQuery( environment, preloadableConcreteRequest, variables, @@ -475,7 +468,7 @@ describe('loadQuery', () => { it('calling dispose after the AST loads unsubscribes from executeWithSource', () => { // This ensures that no data is written to the store - const preloadedQuery = loadQuery( + const preloadedQuery = loadQuery( environment, preloadableConcreteRequest, variables, @@ -523,7 +516,7 @@ describe('loadQuery', () => { it('calling dispose after the AST loads unsubscribes from the network request', () => { // This ensures that live queries stop issuing network requests - const preloadedQuery = loadQuery( + const preloadedQuery = loadQuery( environment, preloadableConcreteRequest, variables, @@ -541,7 +534,7 @@ describe('loadQuery', () => { }); it('calling dispose before the AST loads clears the onLoad callback', () => { - const preloadedQuery = loadQuery( + const preloadedQuery = loadQuery( environment, preloadableConcreteRequest, variables, @@ -564,11 +557,7 @@ describe('loadQuery', () => { }); it('passes a callback to onLoad that calls executeWithSource', () => { - loadQuery( - environment, - preloadableConcreteRequest, - variables, - ); + loadQuery(environment, preloadableConcreteRequest, variables); // $FlowFixMe[method-unbinding] added when improving typing for this parameters expect(environment.executeWithSource).not.toHaveBeenCalled(); executeOnloadCallback(query); @@ -593,7 +582,7 @@ describe('loadQuery', () => { describe("with fetchPolicy === 'store-only'", () => { it('should not call fetch if the query can be fulfilled by the store', () => { - const {source} = loadQuery( + const {source} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -612,7 +601,7 @@ describe('loadQuery', () => { it('should not call fetch if the query cannot be fulfilled by the store', () => { mockAvailability = {status: 'missing'}; - const {source} = loadQuery( + const {source} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -630,7 +619,7 @@ describe('loadQuery', () => { }); it('calling dispose releases the query', () => { - const preloadedQuery = loadQuery( + const preloadedQuery = loadQuery( environment, preloadableConcreteRequest, variables, @@ -646,13 +635,13 @@ describe('loadQuery', () => { describe('when passed a query AST', () => { it('checks whether the query can be fulfilled by the store synchronously', () => { - loadQuery(environment, query, variables); + loadQuery(environment, query, variables); // $FlowFixMe[method-unbinding] added when improving typing for this parameters expect(environment.check).toHaveBeenCalled(); }); describe('when the query can be fulfilled by the store', () => { it("when fetchPolicy === 'store-or-network', it avoids a network request", () => { - loadQuery(environment, query, variables, { + loadQuery(environment, query, variables, { fetchPolicy: 'store-or-network', }); expect(fetch).not.toHaveBeenCalled(); @@ -665,14 +654,9 @@ describe('loadQuery', () => { describe("when fetchPolicy === 'network-only'", () => { it('should make a network request', done => { - const {source} = loadQuery( - environment, - query, - variables, - { - fetchPolicy: 'network-only', - }, - ); + const {source} = loadQuery(environment, query, variables, { + fetchPolicy: 'network-only', + }); const nextCallback = jest.fn(() => done()); if (source) { // $FlowFixMe[incompatible-call] Error found while enabling LTI on this file @@ -705,14 +689,9 @@ describe('loadQuery', () => { }); it('should mark failed network requests', () => { - const preloadedQuery = loadQuery( - environment, - query, - variables, - { - fetchPolicy: 'network-only', - }, - ); + const preloadedQuery = loadQuery(environment, query, variables, { + fetchPolicy: 'network-only', + }); expect(preloadedQuery.networkError).toBeNull(); @@ -724,14 +703,9 @@ describe('loadQuery', () => { it('calling dispose unsubscribes from environment.executeWithSource', () => { // This ensures that no data is written to the store - const preloadedQuery = loadQuery( - environment, - query, - variables, - { - fetchPolicy: 'network-only', - }, - ); + const preloadedQuery = loadQuery(environment, query, variables, { + fetchPolicy: 'network-only', + }); expect(fetch).toHaveBeenCalled(); // $FlowFixMe[method-unbinding] added when improving typing for this parameters expect(environment.executeWithSource).toHaveBeenCalledTimes(1); @@ -768,14 +742,9 @@ describe('loadQuery', () => { it('calling dispose unsubscribes from the network request', () => { // This ensures that live queries stop issuing network requests - const preloadedQuery = loadQuery( - environment, - query, - variables, - { - fetchPolicy: 'network-only', - }, - ); + const preloadedQuery = loadQuery(environment, query, variables, { + fetchPolicy: 'network-only', + }); preloadedQuery.dispose(); expect(networkUnsubscribe).not.toBe(null); @@ -792,11 +761,7 @@ describe('loadQuery', () => { }); it('should make a network request', done => { - const {source} = loadQuery( - environment, - query, - variables, - ); + const {source} = loadQuery(environment, query, variables); const nextCallback = jest.fn(() => done()); if (source) { // $FlowFixMe[incompatible-call] Error found while enabling LTI on this file @@ -829,11 +794,7 @@ describe('loadQuery', () => { }); it('should mark failed network requests', () => { - const preloadedQuery = loadQuery( - environment, - query, - variables, - ); + const preloadedQuery = loadQuery(environment, query, variables); expect(preloadedQuery.networkError).toBeNull(); @@ -845,11 +806,7 @@ describe('loadQuery', () => { it('calling dispose unsubscribes from environment.executeWithSource', () => { // This ensures that no data is written to the store - const preloadedQuery = loadQuery( - environment, - query, - variables, - ); + const preloadedQuery = loadQuery(environment, query, variables); expect(fetch).toHaveBeenCalled(); // $FlowFixMe[method-unbinding] added when improving typing for this parameters expect(environment.executeWithSource).toHaveBeenCalledTimes(1); @@ -874,11 +831,7 @@ describe('loadQuery', () => { it('calling dispose unsubscribes from the network request', () => { // This ensures that live queries stop issuing network requests - const preloadedQuery = loadQuery( - environment, - query, - variables, - ); + const preloadedQuery = loadQuery(environment, query, variables); preloadedQuery.dispose(); expect(networkUnsubscribe).not.toBe(null); @@ -890,7 +843,7 @@ describe('loadQuery', () => { describe("with fetchPolicy === 'store-only'", () => { it('should not call fetch if the query can be fulfilled by the store', () => { - const {source} = loadQuery( + const {source} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -909,7 +862,7 @@ describe('loadQuery', () => { it('should not call fetch if the query cannot be fulfilled by the store', () => { mockAvailability = {status: 'missing'}; - const {source} = loadQuery( + const {source} = loadQuery( environment, preloadableConcreteRequest, variables, @@ -927,7 +880,7 @@ describe('loadQuery', () => { }); it('calling dispose releases the query', () => { - const preloadedQuery = loadQuery( + const preloadedQuery = loadQuery( environment, preloadableConcreteRequest, variables, @@ -951,15 +904,10 @@ describe('loadQuery', () => { return props.children; }; LoadDuringRender = (props: {name?: ?string}) => { - loadQuery( - environment, - preloadableConcreteRequest, - variables, - { - fetchPolicy: 'store-or-network', - __nameForWarning: props.name, - }, - ); + loadQuery(environment, preloadableConcreteRequest, variables, { + fetchPolicy: 'store-or-network', + __nameForWarning: props.name, + }); return null; }; }); diff --git a/packages/react-relay/relay-hooks/__tests__/usePreloadedQuery-test.js b/packages/react-relay/relay-hooks/__tests__/usePreloadedQuery-test.js index 386486e23c4ab..64b66e0468569 100644 --- a/packages/react-relay/relay-hooks/__tests__/usePreloadedQuery-test.js +++ b/packages/react-relay/relay-hooks/__tests__/usePreloadedQuery-test.js @@ -12,6 +12,8 @@ 'use strict'; import type {Sink} from '../../../relay-runtime/network/RelayObservable'; +import type {PreloadableConcreteRequest} from '../EntryPointTypes.flow'; +import type {usePreloadedQueryTestQuery} from './__generated__/usePreloadedQueryTestQuery.graphql'; import type {GraphQLResponse} from 'relay-runtime/network/RelayNetworkTypes'; const {loadQuery} = require('../loadQuery'); @@ -51,10 +53,11 @@ const query = graphql` const ID = '12345'; (query.params: $FlowFixMe).id = ID; -const preloadableConcreteRequest = { - kind: 'PreloadableConcreteRequest', - params: query.params, -}; +const preloadableConcreteRequest: PreloadableConcreteRequest = + { + kind: 'PreloadableConcreteRequest', + params: query.params, + }; const response = { data: { @@ -559,13 +562,9 @@ describe.each([ describe('if loadQuery is passed a preloadableConcreteRequest which is not available synchronously', () => { it('does not suspend while the query is pending until the query AST and network response are available', () => { - const prefetched = loadQuery( - environment, - preloadableConcreteRequest, - { - id: '4', - }, - ); + const prefetched = loadQuery(environment, preloadableConcreteRequest, { + id: '4', + }); let data; function Component(props: any) { data = usePreloadedQuery(query, props.prefetched); @@ -606,13 +605,9 @@ describe.each([ }); it('does not suspend while the query is pending until the network response and the query AST are available', () => { - const prefetched = loadQuery( - environment, - preloadableConcreteRequest, - { - id: '4', - }, - ); + const prefetched = loadQuery(environment, preloadableConcreteRequest, { + id: '4', + }); let data; function Component(props: any) { data = usePreloadedQuery(query, props.prefetched); @@ -653,13 +648,9 @@ describe.each([ }); it('renders synchronously if the query has already completed', () => { - const prefetched = loadQuery( - environment, - preloadableConcreteRequest, - { - id: '4', - }, - ); + const prefetched = loadQuery(environment, preloadableConcreteRequest, { + id: '4', + }); let data; PreloadableQueryRegistry.set(ID, query); expect(dataSource).toBeDefined(); @@ -690,13 +681,9 @@ describe.each([ }); it('renders an error synchronously if the query has already errored', () => { - const prefetched = loadQuery( - environment, - preloadableConcreteRequest, - { - id: '4', - }, - ); + const prefetched = loadQuery(environment, preloadableConcreteRequest, { + id: '4', + }); let data; PreloadableQueryRegistry.set(ID, query); expect(dataSource).toBeDefined(); @@ -726,7 +713,7 @@ describe.each([ describe('when loadQuery is passed a query AST', () => { describe('when the network response is available before usePreloadedQuery is rendered', () => { it('should synchronously render successfully', () => { - const prefetched = loadQuery(environment, query, { + const prefetched = loadQuery(environment, query, { id: '4', }); let data; @@ -757,7 +744,7 @@ describe.each([ }); }); it('should synchronously render errors', () => { - const prefetched = loadQuery(environment, query, { + const prefetched = loadQuery(environment, query, { id: '4', }); let data; @@ -787,7 +774,7 @@ describe.each([ describe('when the network response occurs after usePreloadedQuery is rendered', () => { it('should suspend, and then render', () => { - const prefetched = loadQuery(environment, query, { + const prefetched = loadQuery(environment, query, { id: '4', }); let data; @@ -821,7 +808,7 @@ describe.each([ }); }); it('should suspend, then render and error', () => { - const prefetched = loadQuery(environment, query, { + const prefetched = loadQuery(environment, query, { id: '4', }); let data; @@ -864,7 +851,7 @@ describe.each([ }); describe('when the network response is available before usePreloadedQuery is rendered', () => { it('should synchronously render successfully', () => { - const prefetched = loadQuery( + const prefetched = loadQuery( environment, preloadableConcreteRequest, { @@ -899,7 +886,7 @@ describe.each([ }); }); it('should synchronously render errors', () => { - const prefetched = loadQuery( + const prefetched = loadQuery( environment, preloadableConcreteRequest, { @@ -933,7 +920,7 @@ describe.each([ describe('when the network response occurs after usePreloadedQuery is rendered', () => { it('should suspend, and then render', () => { - const prefetched = loadQuery( + const prefetched = loadQuery( environment, preloadableConcreteRequest, { @@ -971,7 +958,7 @@ describe.each([ }); }); it('should suspend, then render and error', () => { - const prefetched = loadQuery( + const prefetched = loadQuery( environment, preloadableConcreteRequest, { @@ -1022,13 +1009,9 @@ describe.each([ network: Network.create(altFetch), store: new Store(new RecordSource()), }); - const prefetched = loadQuery( - environment, - preloadableConcreteRequest, - { - id: '4', - }, - ); + const prefetched = loadQuery(environment, preloadableConcreteRequest, { + id: '4', + }); let data; expect(dataSource).toBeDefined(); if (dataSource) { @@ -1066,11 +1049,9 @@ describe.each([ const expectWarningMessage = expect.stringMatching( /^usePreloadedQuery\(\): Expected preloadedQuery to not be disposed/, ); - const prefetched = loadQuery( - environment, - preloadableConcreteRequest, - {}, - ); + const prefetched = loadQuery(environment, preloadableConcreteRequest, { + id: '1', + }); function Component(props: any) { const data = usePreloadedQuery(query, props.prefetched); @@ -1107,7 +1088,7 @@ describe.each([ describe('refetching', () => { it('renders updated data correctly when refetching same query and variables', () => { - const loadedFirst = loadQuery( + const loadedFirst = loadQuery( environment, preloadableConcreteRequest, { @@ -1155,7 +1136,7 @@ describe.each([ // Refetch data = undefined; dataSource = undefined; - const loadedSecond = loadQuery( + const loadedSecond = loadQuery( environment, preloadableConcreteRequest, { @@ -1208,7 +1189,7 @@ describe.each([ }); it('renders updated data correctly when refetching different variables', () => { - const loadedFirst = loadQuery( + const loadedFirst = loadQuery( environment, preloadableConcreteRequest, { @@ -1256,7 +1237,7 @@ describe.each([ // Refetch data = undefined; dataSource = undefined; - const loadedSecond = loadQuery( + const loadedSecond = loadQuery( environment, preloadableConcreteRequest, { diff --git a/packages/react-relay/relay-hooks/loadQuery.js b/packages/react-relay/relay-hooks/loadQuery.js index 9d00aed8a7fa5..56049d88f7f45 100644 --- a/packages/react-relay/relay-hooks/loadQuery.js +++ b/packages/react-relay/relay-hooks/loadQuery.js @@ -24,6 +24,7 @@ import type { IEnvironment, OperationDescriptor, OperationType, + Query, RequestIdentifier, RequestParameters, } from 'relay-runtime'; @@ -56,12 +57,31 @@ function useTrackLoadQueryInRender() { } } +type QueryType = T extends Query + ? { + variables: V, + response: D, + rawResponse?: $NonMaybeType, + } + : $Call<(PreloadableConcreteRequest) => T, T>; + +declare function loadQuery< + T, + TEnvironmentProviderOptions = EnvironmentProviderOptions, +>( + environment: IEnvironment, + preloadableRequest: T, + variables: QueryType['variables'], + options?: ?LoadQueryOptions, + environmentProviderOptions?: ?TEnvironmentProviderOptions, +): PreloadedQueryInner, TEnvironmentProviderOptions>; + function loadQuery< TQuery: OperationType, TEnvironmentProviderOptions = EnvironmentProviderOptions, >( environment: IEnvironment, - preloadableRequest: GraphQLTaggedNode | PreloadableConcreteRequest, + preloadableRequest: PreloadableConcreteRequest, variables: TQuery['variables'], options?: ?LoadQueryOptions, environmentProviderOptions?: ?TEnvironmentProviderOptions, diff --git a/packages/react-relay/relay-hooks/useQueryLoader.js b/packages/react-relay/relay-hooks/useQueryLoader.js index e9d294351e483..ba25733f965dc 100644 --- a/packages/react-relay/relay-hooks/useQueryLoader.js +++ b/packages/react-relay/relay-hooks/useQueryLoader.js @@ -195,7 +195,7 @@ function useQueryLoader< } : options; if (isMountedRef.current) { - const updatedQueryReference = loadQuery( + const updatedQueryReference = loadQuery( options?.__environment ?? environment, preloadableRequest, variables,