Apollo-client: useQuery with inline onError function causes infinite loop

Created on 9 Jun 2020  路  11Comments  路  Source: apollographql/apollo-client

Intended outcome:
Using an onError function with useQuery allows a component to recover from network errors:

  const {data, loading} = useQuery(QUERY, {
    onError: (e) => { // do something with e },
  });

Actual outcome:
When a network error occurs and an inline onError function is defined (as show above), an infinite loop occurs, causing useQuery to make repeated requests indefinitely.

Note: This issue does not occur when a "stable reference" to a function is supplied as a value for onError.

// This version works without issue.
const onError = () => {};
function Component() {
  const {data, loading} = useQuery(QUERY, {
    onError,
  });
  // ...
}

How to reproduce the issue:

Reproduction on CodeSandBox

import React from 'react';
import ReactDOM from 'react-dom';
import {ApolloClient, HttpLink, InMemoryCache, ApolloProvider, gql, useQuery} from '@apollo/client';

const client = new ApolloClient({
  cache: new InMemoryCache(),
  link: new HttpLink({
    uri: 'https://forceNetworkError',
  }),
});

const QUERY = gql`
  query {
    aField
  }
`;

const Root = () => {
  return (
    <ApolloProvider client={client}>
      <Component />
    </ApolloProvider>
  );
};

// Replacing the inline version of onError (in useQuery below) with this fixes the issue.
// const onErrorStableReference = () => {}; 

let renderCount = 0;

function Component() {
  renderCount++;
  if (renderCount === 100) {
    throw new Error("That's enough :)");
  }

  const {loading, error} = useQuery(QUERY, {
    onError: () => {},
    // onErrorStableReference,
  });

  if (error) return <p>Error loading query :(</p>;
  else if (loading) return <p>Loading query...</p>;
  else return <p>We'll never get here</p>;
}

ReactDOM.render(<Root />, document.getElementById('root'));

Versions

  System:
    OS: macOS Mojave 10.14.6
  Binaries:
    Node: 14.1.0 - /usr/local/bin/node
    npm: 6.14.4 - /usr/local/bin/npm
  Browsers:
    Chrome: 83.0.4103.97
  npmPackages:
    @apollo/client: 3.0.0-rc.2 => 3.0.0-rc.2
    react: 16.13.1
馃洭 fixed-in-prerelease

Most helpful comment

I just encountered this and put together an example as well before I discovered this issue. As it turns out, if you return any false-y value from your onError handler then the infinite loop occurs, but any truth-y thing will break the infinite loop.

All 11 comments

Using useQuery with "network-only" fetch policy seems to also trigger a loop.

The combination of an inline error handler and cache-and-network fetch policy seems to cause this too.

If you use useCallback like this code, the problem will be resolved!
Btw I'll look into the code and find the reason ASAP.

I think the same issue happens with onCompleted too.

I just encountered this and put together an example as well before I discovered this issue. As it turns out, if you return any false-y value from your onError handler then the infinite loop occurs, but any truth-y thing will break the infinite loop.

Can confirm that this happens with onCompleted as well, and the above suggestion to use a stable reference from useCallback fixes the issues. We're on rc.8.

I just encountered this and put together an example as well before I discovered this issue. As it turns out, if you return any false-y value from your onError handler then the infinite loop occurs, but any truth-y thing will break the infinite loop.

This no longer works in latest stuff, but the useCallback solution does. 馃憤

This is still happening even with the official v3 release. The component infinitely rerenders and fetches if I pass an onCompleted fn.

I believe the fix will land in the next version as it was merged only 2 days ago
https://github.com/apollographql/apollo-client/pull/6588

Update to @apollo/[email protected] version while v3.1.0 is not published.

I can confirm that with @apollo/[email protected] this is fixed. Thank You.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jamesreggio picture jamesreggio  路  3Comments

gregorskii picture gregorskii  路  3Comments

kriswep picture kriswep  路  3Comments

stubailo picture stubailo  路  3Comments

MichaelDeBoey picture MichaelDeBoey  路  3Comments