relay-tools / relay-hooks

Use Relay as React hooks
https://relay-tools.github.io/relay-hooks/docs/relay-hooks.html
MIT License
540 stars 56 forks source link

Disable fetch-on-render in SSR #147

Closed kesne closed 3 years ago

kesne commented 3 years ago

I'm working in a server-side rendered application, and noticing that relay-hooks fetches the query on render on the server (as opposed to in an effect, which would only run on the client).

Because of this, my server is making extra GraphQL requests, the results of which are not being used because the SSR response has already been sent.

I imagine fetching on render should either be disabled for SSR, or perhaps there could be a flag to globally disable it that users could define for SSR apps.

morrys commented 3 years ago

Hi @kesne, the useQuery is designed to run on the server just like the HOC QueryRenderer. This is to give the possibility to implement a complete SSR (an example can be found here: pagination-nextjs-ssr).

If I understand correctly you would like to render the page on the server without executing the query, therefore in a loading state. To do this you can use the useQuery property skip: https://github.com/relay-tools/relay-hooks/commit/8bb54c304460c3a3b2f45272081926ba0a3ba275

kesne commented 3 years ago

What’s the point of issuing the request during the server mount if it’s technically impossible for the result to be used? The only case where that would make sense is with suspense.

kesne commented 3 years ago

I’m not fully sure about the skip property. The queries shouldn’t just be in a loading state, they should still read the current data from the store if it exists, they just shouldn’t try to fetch it

morrys commented 3 years ago

What you describe is the store-only policy: store-only: Reuse data cached in the store; never send a network request.

kesne commented 3 years ago

Is there a way to globally configure the cache policy? It seems like store-only is the only sensible cache policy for server side rendering.

morrys commented 3 years ago

A global way to configure it no, as these kinds of configurations I would introduce them in the relay environment (relay-runtime)

kesne commented 3 years ago

It just seems confusing why the default implementation on the server is to initiate fetches. Given that, my recommendation to anyone using Relay on the server would be to create a fake environment that does not actually initiate network fetches on the server. Otherwise, as it stands today, all relay apps on the server are performing unnessecary work.

morrys commented 3 years ago

Furthermore, in react-relay (non-experimental) there are only store-and-network & network-only policies

morrys commented 3 years ago

@kesne let me know how it goes, otherwise we can evaluate other solutions and then propose them in react-relay too 👍

kesne commented 3 years ago

@morrys My workaround works fine, it's just really unfortunate to have to do it. I imagine the most ideal solution is to pre-load all queries on the server, but it's not always practical to do that.

I suppose the alternative is to make sure that I manually skip all queries that are not pre-loaded, and then make the default environment throw an error when it attempts to fetch instead.

Anyway, I'm fine with this being the same as relay, given there are workarounds.

sibelius commented 3 years ago

you should check relay entrypoints, it could solve some problems for you

the best fetch policy for ssr is store-or-network