diff --git a/src/core/watchQueryOptions.ts b/src/core/watchQueryOptions.ts index 934ab26f62a..c4ddaa47dfc 100644 --- a/src/core/watchQueryOptions.ts +++ b/src/core/watchQueryOptions.ts @@ -110,6 +110,11 @@ export interface ModifiableWatchQueryOptions * Apollo Client `QueryManager` (due to a cache miss). */ partialRefetch?: boolean; + + /** + * If set to `true`, the result data will be discarded while the `refetch` query is in flight. + */ + clearPreviousDataOnLoad?: boolean; } /** diff --git a/src/react/data/QueryData.ts b/src/react/data/QueryData.ts index 673e5df55bf..21287910e95 100644 --- a/src/react/data/QueryData.ts +++ b/src/react/data/QueryData.ts @@ -420,7 +420,11 @@ export class QueryData extends OperationData { this.setOptions(options, true); this.previousData.loading = this.previousData.result && this.previousData.result.loading || false; - return this.previousData.result = result; + this.previousData.result = result; + if (result.loading && options.clearPreviousDataOnLoad) { + result.data = undefined; + } + return result; } private handleErrorOrCompleted({ diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index a439d7aef7b..b7afeee66ea 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -1116,6 +1116,123 @@ describe('useQuery Hook', () => { expect(renderCount).toBe(6); }); }); + + it('should properly handle clearPreviousDataOnLoad', async () => { + const carQuery: DocumentNode = gql` + query cars($id: Int) { + cars(id: $id) { + id + make + model + vin + __typename + } + } + `; + + const carData1 = { + cars: [ + { + id: 1, + make: 'Audi', + model: 'RS8', + vin: 'DOLLADOLLABILL', + __typename: 'Car' + } + ] + }; + + const carData2 = { + cars: [ + { + id: 2, + make: 'Audi', + model: 'eTron', + vin: 'TREESRGOOD', + __typename: 'Car' + } + ] + }; + + const carData3 = { + cars: [ + { + id: 3, + make: 'BMW', + model: '335xi', + vin: 'SUPERFAST', + __typename: 'Car' + } + ] + }; + + const mocks = [ + { + request: { query: carQuery, variables: { id: 1 } }, + result: { data: carData1 } + }, + { + request: { query: carQuery, variables: { id: 2 } }, + result: { data: carData2 } + }, + { + request: { query: carQuery, variables: { id: 3 } }, + result: { data: carData3 } + } + ]; + + let renderCount = 0; + function App() { + const { loading, data, refetch } = useQuery(carQuery, { + variables: { + id: 1 + }, + clearPreviousDataOnLoad: true + }); + + switch (renderCount) { + case 0: + expect(loading).toBeTruthy(); + break; + case 1: + expect(loading).toBeFalsy(); + expect(data).toEqual(carData1); + refetch({ id: 2 }); + break; + case 2: + expect(loading).toBeTruthy(); + expect(data).not.toBeDefined(); + break; + case 3: + expect(loading).toBeFalsy(); + expect(data).toEqual(carData2); + refetch({ id: 3 }); + break; + case 4: + expect(loading).toBeTruthy(); + expect(data).not.toBeDefined(); + break; + case 5: + expect(loading).toBeFalsy(); + expect(data).toEqual(carData3); + break; + default: + } + + renderCount += 1; + return null; + } + + render( + + + + ); + + return wait(() => { + expect(renderCount).toBe(6); + }); + }); }); describe('Partial refetching', () => { diff --git a/src/react/types/types.ts b/src/react/types/types.ts index e8e3eacab40..945ccc70209 100644 --- a/src/react/types/types.ts +++ b/src/react/types/types.ts @@ -41,6 +41,7 @@ export interface BaseQueryOptions { context?: Context; partialRefetch?: boolean; returnPartialData?: boolean; + clearPreviousDataOnLoad?: boolean; } export interface QueryFunctionOptions<