diff --git a/src/react/data/QueryData.ts b/src/react/data/QueryData.ts index 4d3ad689830..d311b0c05ea 100644 --- a/src/react/data/QueryData.ts +++ b/src/react/data/QueryData.ts @@ -27,6 +27,8 @@ import { } from '../types/types'; import { OperationData } from './OperationData'; +const stripFns = ({ onCompleted, onError, ...rest }: any = {}) => rest; + export class QueryData extends OperationData { public onNewData: () => void; @@ -239,12 +241,15 @@ export class QueryData extends OperationData { children: null }; - if ( - !equal( - newObservableQueryOptions, - this.previousData.observableQueryOptions - ) - ) { + // When comparing new options against previously stored options, + // we'll ignore callback functions since their identities are not + // stable, meaning they'll always show as being different. Ignoring + // them when determining if options have changed is okay however, as + // callback functions are not normally changed between renders. + if (!equal( + stripFns(newObservableQueryOptions), + stripFns(this.previousData.observableQueryOptions), + )) { this.previousData.observableQueryOptions = newObservableQueryOptions; this.currentObservable .setOptions(newObservableQueryOptions) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 9ec841088e5..1787d437494 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -1798,6 +1798,43 @@ describe('useQuery Hook', () => { expect(renderCount).toBe(3); }).then(resolve, reject); }); + + itAsync( + 'should not make extra network requests when `onCompleted` is ' + + 'defined with a `network-only` fetch policy', + (resolve, reject) => { + let renderCount = 0; + function Component() { + const { loading, data } = useQuery(CAR_QUERY, { + fetchPolicy: 'network-only', + onCompleted: () => undefined + }); + switch (++renderCount) { + case 1: + expect(loading).toBeTruthy(); + break; + case 2: + expect(loading).toBeFalsy(); + expect(data).toEqual(CAR_RESULT_DATA); + break; + case 3: + fail('Too many renders'); + default: + } + return null; + } + + render( + + + + ); + + return wait(() => { + expect(renderCount).toBe(2); + }).then(resolve, reject); + } + ); }); describe('Optimistic data', () => {