trojanowski/react-apollo-hooks

Using fetchPolicy: 'cache-and-network' creates infinite loop

nicolaslopezj opened this issue ยท 6 comments

Using the options cache-and-network for fetch policy creates an infinite loop.

I could see that in this if:

query === previousQuery.current &&
isEqual(variables, previousVariables.current) &&
isEqual(apolloContextOptions, previousApolloContextOptions.current) &&
isEqual(restOptions, previousRestOptions.current)

previousVariables.current and previousRestOptions.current and always undefined.

I don't know why useRef is not persisting.

The infinite loop is caused by suspense. A component using the useQuery hook with cache-and-network fetch policy ignores local cache, starts fetching fresh data and throws a promise as a signal to react to suspend the tree. React then renders fallback and when data finishes loading tries to render the component again. But the cache is ignored again causing the loop. I created #15 which partially solves the problem - I'm emulating the cache-and-network policy by using the default cache-first one and then optionally forcing a refetch. The problem with that that the refetch is also invoked the first time the page is loading.

I also added a workaround in db119e5. You can now invoke the hook as useQuery(THE_QUERY, { suspend: false }) and manage the loading state by yourself, similar to how react-apollo does. It's published in the 0.1.5 version.

@trojanowski what's the reason it ignores the local cache? Is that a bug in react-apollo itself?

The infinite look was caused because:

  1. We were using the currentResult.partial flag to check if we had a full result in the cache:
    if (currentResult.partial) {
  2. This flag was always initially set to true if cache-and-network fetch policy was used, even if we had the full result.
  3. Because of 2. React suspended the tree what caused the hook to be "restarted" and a new observableQuery was created (in a loop).

We should be able to emulate cache-and-network by ourselves (I tried it in #15), but it's not a priority for me (but I'd accept a PR).

I'm going to close this issue because the loop doesn't happen in the non-suspense mode, and it's not currently possible to use it with suspend: true (there's an error thrown in that case). I added a lack of support for non-standard fetch policies to the known suspense-only issues in #88.

I've made a rewrite of your useQuery hook and it works with any fetchPolicy, you can check it here https://github.com/nicolaslopezj/apollo-hooks/blob/master/src/useQueryBase.js

namnm commented

@trojanowski Do you think the changes @nicolaslopezj can be merged?

@trojanowski the changes was merged? or any support was added for this?