Open siamahnaf opened 1 week ago
Hmm, regarding refetching, useQuery
shouldn't behave differently from useSuspenseQuery
. That's certainly weird. I'll bring this up with my colleagues, but unfortunately that will have to wait a few days as they're all out for a conference right now.
Afaik, you cannot use queryKey
for refetching, but for now you could use one of the alternative notations for refetchQueries
, e.g. refetchQueries: [CATEGORY_LIST],
or refetchQueries: [{ query: CATEGORY_LIST, variables: { searchDto: pagination }}]
As for global errorPolicy
for useSuspenseQuery
: That is currently not possible, as we will give you different return types depending on your errorPolicy
, and the moment you'd define that globally, we'd have to somehow react to that with the types, which is not possible in TypeScript.
Thank you @phryneas. You are superstar, as you always provide us solutions.
Summary of my main issues, which can be discussed with your colleagues-
useQuery
hook is not picking data from PreloadQuery
component as like useSuspenseQuery
useSuspenseQuery
is not refetching or updating data after mutation, when it's errorPolicy
is it's default. Work when errorPolicy
is set to network-only
@siamahnaf on second thought, for 1., could you please check if there is actually a network request starting on the client? useQuery
has to still wait for the data to actually arrive in the cache, so it goes got "loading", even if that loading happens on the server and is streamed over with PreloadQuery
. It cannot "pause" rendering like useSuspenseQuery
can.
You just don't see it as an "active query" in the devtools, but that doesn't mean it doesn't fetch that data.
Take a look at the Cache
tab of the devtools - it should appear there once it's fetched on the server.
@phryneas, yes you are right. Sorry for misinformation. But I can share something with more behavior if you can understand it-
If I use directly useSuspenseQuery
without wrapping PreloadQuery
const Page = async () => {
return (
<Lists /> //In this component I use useSuspenseQuery
);
};
export default Page;
https://github.com/user-attachments/assets/8c8fdb14-0838-4b13-b6f1-c3141575032e
If I use PreloadQuery
-
const Page = async () => {
return (
<PreloadQuery query={CATEGORY_LIST} variables={{ searchDto: defaultSearch }}>
<div>Hello World</div>
</PreloadQuery>
);
};
export default Page;
https://github.com/user-attachments/assets/421849f0-e3b7-4b30-a550-d5dfe5160066
Cached data coming after first load. Is it any issue?
PreloadQuery
not running on ssr, that's why useQuery
getting failed to pick data from cache into SSR?@phryneas,
I do another test-
const Page = () => {
return (
<PreloadQuery query={CATEGORY_LIST} variables={{ searchDto: { limit: 1 } }} errorPolicy="all" fetchPolicy="cache-first">
<Lists />
</PreloadQuery>
);
};
export default Page;
Here I give limit: 1
as variable. On the other hand I give limit: 2
on useSuspenseQuery
-
const { data } = useSuspenseQuery(CATEGORY_LIST, { variables: { searchDto: { limit: 2 } } });
See the following video
https://github.com/user-attachments/assets/6c61a098-0009-4e17-86b3-38cb3c297d58
useSuspenseQuery
caching data before PreloadQuery
Component.
**Updated I found something more-
PreloadQuery
is not transport data into client component-
<script>
(window[Symbol.for("ApolloSSRDataTransport")] ??= []).push({
"rehydrate": {
":R2pvj6:": {
"data": {
"getProfile": {
"__typename": "User",
"id": "2",
"name": "Siam Ahnaf",
"phone": "01611994403",
"email": "siamahnaf198@gmail.com",
"avatar": null,
"is_verified": true,
"role": "admin"
}
},
"networkStatus": 7
},
":R4pvj6:": {
"data": {
"getProfile": {
"__typename": "User",
"id": "2",
"name": "Siam Ahnaf",
"phone": "01611994403",
"email": "siamahnaf198@gmail.com",
"avatar": null,
"is_verified": true,
"role": "admin"
}
},
"networkStatus": 7
}
},
"events": [{
"type": "started",
"options": {
"fetchPolicy": "cache-first",
"query": "query getProfile{getProfile{id name phone email avatar is_verified role}}",
"notifyOnNetworkStatusChange": false,
"nextFetchPolicy": undefined
},
"id": "1"
}, {
"type": "data",
"id": "1",
"result": {
"data": {
"getProfile": {
"__typename": "User",
"id": "2",
"name": "Siam Ahnaf",
"phone": "01611994403",
"email": "siamahnaf198@gmail.com",
"avatar": null,
"is_verified": true,
"role": "admin"
}
}
}
}, {
"type": "complete",
"id": "1"
}]
})
</script>
Here is no category information,
const Page = async () => {
return (
<PreloadQuery query={CATEGORY_LIST} variables={{ searchDto: defaultSearch }}>
<div></div>
</PreloadQuery>
);
};
export default Page;
No category list is transporting.
PreloadQuery
uses a different transport mechanism, it doesn't inject HTML into your page, it uses a Promise
prop, which is then transported by React.
Turn on debugging via
import { setVerbosity } from "ts-invariant";
setVerbosity("debug");
to see the data transported.
And yes, if you query for two different things in PreloadQuery
and useSuspenseQuery
, those will transport independently from each other. But if you query both for the same thing and useSuspenseQuery
is a child of PreloadQuery
, useSuspenseQuery
will not start an additional network request.
@phryneas, then I don't know. But issues is useQuery
is not picking data from PrealoadQuery
on SSR, instead it pick after page load.
I am seeing that, useQuery
not placing any network request.
useQuery
will usually not pick up any data during SSR because SSR renders only once and useQuery
cannot "pause" your render until a response has finally arrived - it has to work synchronously.
The only way useQuery
will pick up data during SSR is if you deliberately pause the rendering using suspense in a parent component until the data is there and only after that start rendering the component calling useQuery
- but that's kinda flimsy.
If you really need this to cleanly be SSRed, you probably cannot rely on a non-suspense API like useQuery
- that only really works in the browser.
I found one solutions, as your previous text. It's my last question, please don't mind-
I am showing list, on list
page.
And I am creating record from add-new
page
Previously I just try to refetch list page useSuspenseQuery
from add-new
page mutation like following way-
const [mutate, { loading }] = useMutation(ADD_CATEGORY, {
onCompleted: (data) => {
toast.success(data.addCategory.message);
reset();
},
onError: (error) => {
toast.error(error.message)
},
refetchQueries: [CATEGORY_LIST],
awaitRefetchQueries: true
});
But now I change to like-
refetchQueries: [{ query: CATEGORY_LIST, variables: { searchDto: defaultSearch } }]
It's now refetching data and updating useSuspenseQuery
cached.
Questions why previously it was not working.
It's my last questions, As I get solutions.
I don't know right now, I'll have to check in with my colleagues on that one next week. It should refetch.
Okay, thanks you are very helping man. By getting your help, at least I get one solutions. For keeping minimal code, it should refetch with only the queryName or query itself. So I will wait for your next response in next week. Thank you.
Yeah, all we can say is that this really should refetch and we've never had reports of this problem before. Could you maybe create a smaller, self-contained version of the problem that we can run ourselves and experiment in?
I am using
@apollo/client
with nextjs package.What I do in my code-
page.tsx
-Here I do not use "Suspense" boundary because on the nextjs package documents, they said it is optional
Lists.tsx
-Here I add
refetchQueries
. It re-fetching the updating the data.But from another component,
Add.tsx
andEdit.tsx
from another page, I also addrefetchQuerues
with same queryName. In this case it's not updating the data.But-
if I add
fetchPolicy
tonetwork-only
into thisuseSuspenseQuery
then it updating data. That's means it not showing data fromPreloadQuery
component.What is the best approach for my implementation. My only requirement is SSR data fetch, I don't want to show any loading screen or icon.
Here is my repository- https://github.com/siamahnaf/nextjs-apollo-client
If I use
useQuery
insteaduseQuerySuspense
on that case refetch working perfect. But I am not understanding why I see a flash.with
useQuery
-https://github.com/user-attachments/assets/bd14585a-9d3d-4ee5-abb5-2a6a678b1d62
Here you can see a flash. That's means
useQuery
hook are not using data fromPreloadQuery
component.with
useSuspenseQueury
https://github.com/user-attachments/assets/99bfb114-3a9d-4864-b753-2e3e20312c1f
it is not giving flash, but data is not updating when refetch after mutation.
A outside question-
useQuery
,useSuspenseQuery
has aqueryKey
parameter. are we can use thisqueryKey
for refetch data from mutation?errorPolicy
foruseSuspenseQuery
in globally onApolloClient
creation.