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

When more than one useQuery hook is used network requests double #7196

Closed
kolesan opened this issue Oct 20, 2020 · 5 comments
Closed

When more than one useQuery hook is used network requests double #7196

kolesan opened this issue Oct 20, 2020 · 5 comments

Comments

@kolesan
Copy link

kolesan commented Oct 20, 2020

Intended outcome:
Two useQuery hooks with different queries (difference has to be in the sub fields) produce two network requests

Actual outcome:
Two useQuery hooks with different queries (difference has to be in the sub fields) produce three network requests

How to reproduce the issue:
Repo with reproduction: https://github.com/kolesan/react-apollo-error-template

npm start
go to network tab
refresh the page
observe three requests to the api instead of two

Versions
System:
OS: Windows 7 6.1.7601
Binaries:
Node: 13.8.0 - D:\nodejs\node.EXE
Yarn: 1.22.4 - ~\AppData\Roaming\npm\yarn.CMD
npm: 6.13.6 - D:\nodejs\npm.CMD
Browsers:
Chrome: 86.0.4240.75
npmPackages:
@apollo/client: ^3.2.0 => 3.2.0

reproducible on 3.2.1 and 3.2.5 as well

@benjamn
Copy link
Member

benjamn commented Oct 20, 2020

@kolesan You have a couple of good options here, but the root of the issue is that the cache can't tell when it's safe to merge two SiteStatistics objects (see #5603 for explanation of why automatically merging is not safe, even though that's what happened in AC2).

First, have a look at the browser console, where you'll see a detailed warning about this problem (thanks to #6372):

Cache data may be lost when replacing the SiteStatistics field of a Query object.

To address this problem (which is not a bug in Apollo Client), either ensure all objects of type SiteStatistics have an ID or a custom merge function, or define a custom merge function for the Query.SiteStatistics field, so InMemoryCache can safely merge these objects:

  existing: {"__typename":"SiteStatistics","manga":...}
  incoming: {"__typename":"SiteStatistics","anime":...}

For more information about these options, please refer to the documentation:

  * Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers
  * Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects

Giving the SiteStatistics object a unique id will solve the problem, because the cache will be able to tell that you're getting the same SiteStatistics object (just with different fields) each time, so it can safely merge the fields.

Alternatively, if there is only ever one SiteStatistics object (a singleton) in your application, you can configure keyFields: [] to use a constant ID (like SiteStatistics:{}) for these objects, which has a similar effect to giving them a unique id.

If neither of those options works for you, you can explicitly permit the values of the Query.SiteStatistics field to be merged, regardless of their identity:

new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        SiteStatistics: {
          merge: true,
        },
      },
    },
  },
})

Finally, if you update to the latest beta of Apollo Client 3.3 (npm i @apollo/client@beta), you can now put this merge: true configuration in the SiteStatistics type policy instead of having to configure a field policy for all the fields where a SiteStatistics object could appear (thanks to #7070):

new InMemoryCache({
  typePolicies: {
    SiteStatistics: {
      merge: true,
    },
  },
})

Whatever approach you choose, the important thing is to prevent the second query's results from replacing the first query's results, which is what causes the first query to attempt a second network fetch.

@kolesan
Copy link
Author

kolesan commented Oct 21, 2020

@benjamn Thank you for the quick answer.

I tried your suggestions on my actual project, and through a combination of them managed to solve some of the issues, but not all.

My schema is probably not particularly well designed, due to my lack of experience with graphql and caching.

The last issue I ran in to was related to aliasing. I request the same object with same fragment 3 times, but give it a different alias each time. In this case the keyfields array I provided becomes not as unique as I thought.
Is there a way around that (e.g. using alias as a cache key), or do I have to generate a unique id for each object on the server side?

Is there a way to just tell apollo client to cache by query name or something similarly simple? It will not be as performant, but it would probably suffice in my case.

On a side note, if this might interest you, I managed to reproduce these additional requests without getting the warning in the console.
With:

typePolicies: {
    SiteStatistics : {
       keyFields: [],
    },
}

And 2 queries:

SiteStatistics {
   months {
        month
        goals {
             volume
        }
   }
}

and

SiteStatistics {
   months {
        month
        goals {
             revenue #different field
        }
   }
}

@jettandres
Copy link

+1 for this as I'm also experiencing aliasing issues whenever I use fetchPolicy: 'cache-first'. My query doesn't return anything unless I switch the fetchPolicy back to network-only

@xxleyi
Copy link

xxleyi commented Oct 30, 2021

Is there a way to just tell apollo client to cache by query name or something similarly simple? It will not be as performant, but it would probably suffice in my case.

I also want something like this, so I sent a feature request: #8802

@bignimbus
Copy link
Contributor

Thanks for the feature request @xxleyi - I'm closing this issue. For those coming here with questions regarding this item, please see #8802 🙏🏻

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 14, 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

5 participants