Closed jaydenseric closed 5 years ago
@jaydenseric hey, any news about this one?
Not yet! It's a bug or a feature, depending how you look at it, so it's a low priority for me. I can't think of an easy way for the Query
components to tell when it is the very first render on the client after SSR, so don't load.
I suppose it would be nice to come up with a solution for when preloading on the client too. Say if you preload a route component and then mount it, you probably don't want all the queries to loadOnMount
.
Maybe we introduce a new expires
cache key, so that loadOnMount
only does so if the cache has expired. It might make sense to then introduce a Query
component prop (with a default, say 1s) for the cache expiry time.
That way if the page load takes ages, the client will still helpfully load fresh cache.
@jaydenseric yep, this feature would be really nice. Can I dm you a few other questions somewhere to not pollute this issue?
We can Twitter DM: https://twitter.com/jaydenseric
@jaydenseric seems like I can write you only if you follow me.. 🤦♂️
Having lived with it for a while now, I think I am happy with the current behavior.
@jaydenseric Why? It's wasteful. Using a simple useEffect
with empty dependency array is sufficient to know when the component has been mounted browser-side.
@probablyup useEffect
is already being used to load on mount:
https://github.com/jaydenseric/graphql-react/blob/v8.1.2/src/universal/useGraphQL.mjs#L163
The problem is, there is no way to tell if the component is mounting in the browser for the first time after SSR.
Correct, which is why you need a second useEffect
with an empty dependency array. With empty deps it only fires when mounting in the browser for the first time. https://reactjs.org/docs/hooks-effect.html (See the yellow notes section, paragraph 2)
With empty deps it only fires when mounting in the browser for the first time.
It will fire whenever the component is mounted, not just the first time it is mounted. Components can be mounted and unmounted many times as a user interacts with the page long after the first SSR page load.
Right, but what's the harm in firing it again if the developer fully removes and remounts the component? That seems reasonable, but firing the query again with a completely-same component tree and a valid cache doesn't make sense.
You're just describing the original issue.
I've had an idea though.
As a standalone context and hook (could even be published separately), there could be a context called something like IsFirstMount
that starts true
, then in a hook via useEffect
updates to false
. I'm don't think it needs to be state, as when it changes we don't want to trigger the app to re-render. This context and hook needs to be used at the top app level, above any route components; otherwise loadOnMount
won't work when navigating back and forth between routes.
I'm pretty sure child components mount before their parents do, so if they read from the IsFirstMount
context they can tell if it's the first mount or not. Our useGraphQL
hook could try to read the IsFirstMount
context, and if it exists, and is true
, and there is cache available for the query, decide to bail on loading on mount.
In the end after building it, my idea didn't work because the effect callbacks can be called multiple times in the render storm that happens when the client hydrates. The first time it works, but then it thinks IsFirstMount
is false
for following render passes.
The solution was to add a new GraphQLProvider
component that provides both the GraphQLContext
and a FirstRenderDateContext
, populated by a ref initialised with a new Date()
at first render. Descendant useGraphQL
hooks can check how much time has passed since the initial app render to decide if it is still within the arbitrary duration of time that can be considered the initial client hydration (500ms).
Published in v8.2.0 🚀
At the moment,
Query
components with theloadOnMount
prop automatically fetch fresh data when mounted on the initial page load. This is unnecessary after SSR as the hydrated cache can be assumed to be fresh.While harmless, and in some cases useful (if data becomes stale in the time it takes the page to load), it would be nice to work out how to prevent this to reduce the burden on servers and reduce client network traffic.