T
TanStack7mo ago
xenial-black

setDefaultOptions -> refetchQueries race condition?

I'm trying to set a global meta option that my queryFns will recognize and do a fetch(..., {cache: "reload"}) HTTP request. I came up with this:
const reloadQueries = async () => {
queryClient.setDefaultOptions(produce(queryClient.getDefaultOptions(), (draft) => {
set(draft, ["queries", "meta", "reload"], true)
}));

// this will actually call my queryFn with the old `meta = {}`
await queryClient.refetchQueries({type: "active"})

// this one will make the queryFn finally pass meta.reload == true
await queryClient.refetchQueries({type: "active"})
// TODO: uncomment once I figure out the race condition
// queryClient.setDefaultOptions(produce(queryClient.getDefaultOptions(), (draft) => {
// set(draft, ["queries", "meta", "reload"], false)
// }));
};

// ...
<button onClick={reloadQueries}>Reload queries</button>
const reloadQueries = async () => {
queryClient.setDefaultOptions(produce(queryClient.getDefaultOptions(), (draft) => {
set(draft, ["queries", "meta", "reload"], true)
}));

// this will actually call my queryFn with the old `meta = {}`
await queryClient.refetchQueries({type: "active"})

// this one will make the queryFn finally pass meta.reload == true
await queryClient.refetchQueries({type: "active"})
// TODO: uncomment once I figure out the race condition
// queryClient.setDefaultOptions(produce(queryClient.getDefaultOptions(), (draft) => {
// set(draft, ["queries", "meta", "reload"], false)
// }));
};

// ...
<button onClick={reloadQueries}>Reload queries</button>
My queryFn looks like this:
async function queryFn({signal, meta = {}, client}: {signal: AbortSignal, meta?: Record<string, unknown>, client: QueryClient}) {
console.log("in queryFn", JSON.stringify(meta))
console.log("in queryFn still", JSON.stringify(client.getDefaultOptions().queries))
const response = await fetch(
`${API_URL}/some-enpoint`,
{cache: meta.reload ? "reload" : 'default', /* signal */}
);
// ...
}
async function queryFn({signal, meta = {}, client}: {signal: AbortSignal, meta?: Record<string, unknown>, client: QueryClient}) {
console.log("in queryFn", JSON.stringify(meta))
console.log("in queryFn still", JSON.stringify(client.getDefaultOptions().queries))
const response = await fetch(
`${API_URL}/some-enpoint`,
{cache: meta.reload ? "reload" : 'default', /* signal */}
);
// ...
}
So the result is that after the first refetchQueries, my queryFn gets called with meta === {} but the default options are observable and up to date already, with meta.reload == true. Only by the second refetchQueries are both meta and client.getDefaultOptions().queries.meta the same within queryFn. I also tried it with invalidateQueries (which I looked at the code that it eventually calls refetchQueries and is also awaitable), but the behavior is the same. Am I missing something? I did not expect it to be delayed like this. I could always use client.getDefaultOptions() in my queryFns but I'd rather figure out the root cause.
2 Replies
fascinating-indigo
fascinating-indigo7mo ago
setDefaultOptions is not reactive so it doesn't affect queries that are already in use
xenial-black
xenial-blackOP7mo ago
Would you recommend I use client.getDefaultOptions().queries inside my queryFn then? just for this single meta.reload property that is, and if I have other meta options I'll keep them reactive. Or would that cause other issues potentially?

Did you find this page helpful?