Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useQuery with inline onError function causes infinite loop #6416

Closed
dmin opened this issue Jun 9, 2020 · 12 comments
Closed

useQuery with inline onError function causes infinite loop #6416

dmin opened this issue Jun 9, 2020 · 12 comments

Comments

@dmin
Copy link

dmin commented Jun 9, 2020

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
@IgorPieruccini
Copy link

IgorPieruccini commented Jun 10, 2020

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

@tpict
Copy link
Contributor

tpict commented Jun 16, 2020

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

@Pymossy
Copy link

Pymossy commented Jun 17, 2020

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

@lukeramsden
Copy link

I think the same issue happens with onCompleted too.

@supermonkeybrainz
Copy link

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.

@bwhitty
Copy link
Contributor

bwhitty commented Jul 7, 2020

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.

@supermonkeybrainz
Copy link

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. 👍

@Ericnr
Copy link

Ericnr commented Jul 22, 2020

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

@mtt87
Copy link

mtt87 commented Jul 22, 2020

I believe the fix will land in the next version as it was merged only 2 days ago
#6588

@Tautorn
Copy link

Tautorn commented Jul 24, 2020

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

@benjamn benjamn added this to the Post 3.0 milestone Jul 24, 2020
@proutek
Copy link

proutek commented Jul 27, 2020

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

@hwillson
Copy link
Member

hwillson commented May 3, 2021

As mentioned in #6416 (comment), this has been fixed. Thanks!

@hwillson hwillson closed this as completed May 3, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 15, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests