question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

"Loading" stays true when the same result is returned twice in Apollo Client 3.6.9

See original GitHub issue

This has been a long-standing issue that I’ve seen numerous people bring up, but I may have found the cause.

Here is the problem:

const request = {
  query: gql`
    query test($foo: String) {
      test(foo: $foo) {
        value
      }
    }
  `,
  variables: { foo: "bar" },
  notifyOnNetworkStatusChange: true
};

const observer = client.watchQuery(request);

observer.subscribe({
  next: ({ loading }) => {
    console.log(loading);
  }
});

When the GraphQL query returns the same result successfully and subsequently, even if the variables have changed, the loading flag remains true even after the second request returns successfully. It does not return back to false until the result returns something different than it did the last time.

The expected outcome is that loading flips to true when the request is in flight and then flips back to false after the request completes, even if the result is the same between the two requests.

I believe there’s a good chance this bug is due to this bit of code:

  private reportResult(
    result: ApolloQueryResult<TData>,
    variables: TVariables | undefined,
  ) {
    const lastError = this.getLastError();
    if (lastError || this.isDifferentFromLastResult(result)) {
      if (lastError || !result.partial || this.options.returnPartialData) {
        this.updateLastResult(result, variables);
      }

      iterateObserversSafely(this.observers, 'next', result);
    }
  }

I believe that maybe it was supposed to be:

  private reportResult(
    result: ApolloQueryResult<TData>,
    variables: TVariables | undefined,
  ) {
    const lastError = this.getLastError();
    if (lastError || !result.partial || this.options.returnPartialData || this.isDifferentFromLastResult(result)) {
      this.updateLastResult(result, variables);
      iterateObserversSafely(this.observers, 'next', result);
    }
  }

In the former, the observer will never iterate if the request is successful and the next result is the same as the previous result.

Maybe this was just a minor coding oversight. But it would be nice to get feedback from the Apollo Client team to make sure this aligns with their thinking.

The way I was able to confirm this was the issue is that, when I added a timestamp of the request to the GraphQL API result, the problem was completely gone. So when the result is different with each request, it works as intended. But I shouldn’t have to do this in a production setting.

Note I am running @apollo/client 3.6.9 and graphql 16.6.0, both the newest versions. I am also not using React. So if a fix for this was previously introduced for React, I’m afraid it wouldn’t have fixed the root of the problem in Apollo Client itself.

Many tickets about this have been opened by others, all with suggestions of different workarounds, like changing networkPolicy to network-only, no-cache, or cache-and-network. Or even setting pollInterval to 0. But none of these worked for me, presumably because the root problem seems to be related to the conditions under which the observer will iterate. But it is interesting that the cache is still checked even when using a networkPolicy of no-cache.

Here are some of the related issues I found on this topic:

https://github.com/apollographql/apollo-client/issues/6334 https://github.com/apollographql/apollo-client/issues/9845 https://github.com/apollographql/apollo-client/pull/9844 (another attempted fix, but I wonder if this one was overkill) https://github.com/apollographql/apollo-client/pull/6417 (a merged PR from two years ago attempting to fix this, but not successfully) https://github.com/apollographql/apollo-client/issues/9689 (maybe related) https://github.com/apollographql/apollo-client/issues/9668 (also maybe related)

Would greatly appreciate any insight on this. I currently don’t have any other workarounds other than to add a timestamp to our API, but since we have a public-facing API, this would not be ideal.

Thank you!

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
alessbellcommented, Oct 17, 2022

The fix was just merged and will go out in an upcoming patch release (3.7.1). Thanks all!

3reactions
michaelcbrookcommented, Sep 16, 2022

Hey @hwillson,

This one gave me a run for my money to cut down to a reproduction, but I finally got it:

https://codesandbox.io/s/competent-worker-7qu3p1?file=/src/index.jsx

Turns out there are some more specific criteria that trigger this bug. In working on the reproduction, I found this error only happens under these conditions:

  1. Variables must contain non-primitive values (I confirmed an array of objects creates the issue)
  2. The non-primitive value must change between requests
  3. The next result must be the same as the previous result, even though the variables have changed

Of note, the array of objects is being passed as a JSON GraphQL type via the scalars provided by this package: https://www.npmjs.com/package/graphql-scalars

…but that GraphQLJSON definition is set on the server, not the client…

I have not yet tested whether or not this issue still happens with a natively provided data type instead of a custom scalar, but seeing as though Apollo Client should be naive to that type (I think), that may not have any bearing on the problem, at least in my mind.

But I wanted to get your feedback and see whether that’s consistent with your thinking or not.

As for my proposed solution, I’m less certain now in light of what I found after creating this reproduction. But that’s beyond my knowledge.

Thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Queries - Apollo GraphQL Docs
As long as loading is true (indicating the query is still in flight), the component ... and the second item is the same...
Read more >
@apollo/client | Yarn - Package Manager
While this double-rendering always results in calling useQuery twice, forcing Apollo Client to create and then discard an unnecessary ObservableQuery object, we ...
Read more >
'loading' remains true when loading data with 'useQuery' using ...
Unfortunately, this is a known bug, which happened in apollo client 3.6. The last proper working version was 3.5 ...
Read more >
@apollo/client - Awesome JS
Fix issue where loading remains true after observer.refetch is called repeatedly with different variables when the same data are returned.
Read more >
React Apollo: Understanding Fetch Policy with useQuery
Apollo Client executes the query only against the cache. It never queries your server in this case. A cache-only query throws an error...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found