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:
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
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 youronError
handler then the infinite loop occurs, but anytruth-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.
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 youronError
handler then the infinite loop occurs, but anytruth-y
thing will break the infinite loop.