apollographql / apollo-client

:rocket:  A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server.
https://apollographql.com/client
MIT License
19.38k stars 2.66k forks source link

getDataFromTree renders multiple times even though all queries are already in the cache #10314

Open spetroll opened 1 year ago

spetroll commented 1 year ago

We are using getDataFromTree in our Next.js application to collect all data required before rendering a page on the server. As we know, getDataFromTree runs multiple times when having nested queries to resolve all queries in the AppTree. I hoped to reduce the number of rerenders by prefetching the queries. While the queries cache is primed with all required data, it still has to render the whole AppTree multiple times instead of once. It appears as if getDataFromTree can't make use of the cached queries.

Intended outcome:

getDataFromTree should not ignore cached queries and render only once when all data is available.

Actual outcome:

The cached queries are ignored and nested useQuery causes the whole AppTree to be rendered multiple times with getDataFromTree. (6 in my example)

items in cache before `getDataFromTree` (fetched in `Index.getInitialProps`)
 [
  '__typename',
  'film({"id":"ZmlsbXM6Mg=="})',
  'film({"id":"ZmlsbXM6MQ=="})',
  'film({"id":"ZmlsbXM6Mw=="})',
  'film({"id":"ZmlsbXM6NA=="})',
  'film({"id":"ZmlsbXM6NQ=="})',
  'film({"id":"ZmlsbXM6Ng=="})'
]

useQuery for index=0 (ZmlsbXM6MQ==) returned no-data
useQuery for index=0 (ZmlsbXM6MQ==) returned A New Hope
useQuery for index=1 (ZmlsbXM6Mg==) returned no-data
useQuery for index=0 (ZmlsbXM6MQ==) returned A New Hope
useQuery for index=1 (ZmlsbXM6Mg==) returned The Empire Strikes Back
useQuery for index=2 (ZmlsbXM6Mw==) returned no-data
useQuery for index=0 (ZmlsbXM6MQ==) returned A New Hope
useQuery for index=1 (ZmlsbXM6Mg==) returned The Empire Strikes Back
useQuery for index=2 (ZmlsbXM6Mw==) returned Return of the Jedi
useQuery for index=3 (ZmlsbXM6NA==) returned no-data
useQuery for index=0 (ZmlsbXM6MQ==) returned A New Hope
useQuery for index=1 (ZmlsbXM6Mg==) returned The Empire Strikes Back
useQuery for index=2 (ZmlsbXM6Mw==) returned Return of the Jedi
useQuery for index=3 (ZmlsbXM6NA==) returned The Phantom Menace
useQuery for index=4 (ZmlsbXM6NQ==) returned no-data
useQuery for index=0 (ZmlsbXM6MQ==) returned A New Hope
useQuery for index=1 (ZmlsbXM6Mg==) returned The Empire Strikes Back
useQuery for index=2 (ZmlsbXM6Mw==) returned Return of the Jedi
useQuery for index=3 (ZmlsbXM6NA==) returned The Phantom Menace
useQuery for index=4 (ZmlsbXM6NQ==) returned Attack of the Clones

App was rendered 6 times inside getDataFromTree
useQuery for index=0 (ZmlsbXM6MQ==) returned A New Hope
useQuery for index=1 (ZmlsbXM6Mg==) returned The Empire Strikes Back
useQuery for index=2 (ZmlsbXM6Mw==) returned Return of the Jedi
useQuery for index=3 (ZmlsbXM6NA==) returned The Phantom Menace
useQuery for index=4 (ZmlsbXM6NQ==) returned Attack of the Clones

How to reproduce the issue:

I reproduced this issue in this codesandbox: https://codesandbox.io/p/sandbox/laughing-pasteur-q84rpu

Versions

System: OS: Linux 5.15 Debian GNU/Linux 11 (bullseye) 11 (bullseye) Binaries: Node: 16.17.0 - /usr/local/bin/node Yarn: 1.22.19 - /usr/local/bin/yarn npm: 8.15.0 - /usr/local/bin/npm npmPackages: @apollo/client: 3.7.1 => 3.7.1

jerelmiller commented 1 year ago

Hey @spetroll 👋

I understand this is is not optimal and agree getDataFromTree should try to be a bit more optimized. The good news is that we are focused on improvements to the SSR story with Apollo with React 18's renderToPipeableStream. Take a look at the RFC for more details.

Unfortunately I can't guarantee we will spend much time with getDataFromTree since we will likely encourage users to migrate to the React 18 capabilities, which provide much more robust behavior and UX.

Hopefully this provides you a bit of insight!