T
TanStack3y ago
extended-salmon

useQueries - Accessing meta information in errors

Using V4 Hey 👋 I've tried finding resources on this but came up short. I'm somewhat inspired by the v5 version of useQueries and combine. Say I have a functionality that allows to get customers in multiple systems and then combining the final answer into one long list of customers. I have a simple hook as a wrapper around a query as such;
export const useCustomerQueries = () => {
const queries = useQueries({
queries: systems.map((s) => ({
queryKey: ['customers', s],
queryFn: () => fetchCustomers(s),
meta: { system: s },
...
})),
});

const data = R.filter(
queries.flatMap((q) => q.data?.customers),
R.isDefined
);

return {...}
}
export const useCustomerQueries = () => {
const queries = useQueries({
queries: systems.map((s) => ({
queryKey: ['customers', s],
queryFn: () => fetchCustomers(s),
meta: { system: s },
...
})),
});

const data = R.filter(
queries.flatMap((q) => q.data?.customers),
R.isDefined
);

return {...}
}
Okay so far so good, all customers are being aggregated into a single list. However we have no error handeling - okay so we add a way to retrieve the errors too.
...method
const errors = R.filter(
queries.map((q) => q.error),
R.isDefined
);
...
...method
const errors = R.filter(
queries.map((q) => q.error),
R.isDefined
);
...
But now - as we display a list of errors in the UI, we have no idea where this error came from, just that it happened. We have our meta field on the queries which define the system we're working with, but I see no way to extract the meta field on a query result. The best I can come up with is doing something like this;
...method
const cache = useQueryClient().getQueryCache();
const errors = cache
.findAll(['customers'], {
type: 'active',
predicate: (q) => !!q.state.error,
})
.map((q) => ({ ...q.state.error, meta: q.meta }));
...
...method
const cache = useQueryClient().getQueryCache();
const errors = cache
.findAll(['customers'], {
type: 'active',
predicate: (q) => !!q.state.error,
})
.map((q) => ({ ...q.state.error, meta: q.meta }));
...
Is this approach fine? It feels a little odd to rely on the Query Cache when I am defining my queries a few lines above... Is there a simpler approach that I am missing? Thanks. Stackblitz example: https://stackblitz.com/edit/stackblitz-starters-kov63e?file=src%2Fquery.ts
Emil Dyrhoi
StackBlitz
Multi Query Example w/ meta aware errors - StackBlitz
React + TypeScript starter project
6 Replies
extended-salmon
extended-salmonOP3y ago
I apologize for bumping this question up, but I'd greatly appreciate a discussion since I haven't found a better alternative yet. I'd be happy to provide more information regarding my use case if needed
optimistic-gold
optimistic-gold3y ago
why not map over it and return { data, error, status }, then you have the association. Also, try out v5 and combine - we have a release-candidate out already
extended-salmon
extended-salmonOP3y ago
Thanks for your responsse. Unfortunately I am not able to move to V5 within my company just yet. It's on the schedule. Can you elaborate on what you mean by association in this case? The system which was queried? Just to see if we're on the same page, you're suggesting something like this?
const useCustomersQueries = (systems: System[]) => useQueries(queries: systems.map({...})).map({data, error, status} => ({data, error, status}))
const useCustomersQueries = (systems: System[]) => useQueries(queries: systems.map({...})).map({data, error, status} => ({data, error, status}))
(Sorry for bad / incorrect formatting, on my phone). How do I associate the error with the system.id (used for querykey from argument) in this case? The error object is isolated from what system was called. Or am I misunderstanding?
optimistic-gold
optimistic-gold3y ago
if you want the error to know about why system was fetching it, then include that information in the error you're throwing
extended-salmon
extended-salmonOP3y ago
Ah - so if I was working with an axios error in this instance, I would catch the error in the queryFn and pass whatever system attributes ontop of it - as I don't have control of the backend error response? Such as
const useCustomersQueries = (systems: System[]) => useQueries({queries: systems.map(s => ({
queryKey: ['customers', s.id],
queryFn: () => getCustomersBySystemId(s.id),
...
}))}).map(...)

async function getCustomersBySystemId(systemId: string) {
try {
// Some axios request
return await api.get(`customers/${id}`)
} catch (e) {
// Potentially set extra meta data on the error, to identify the "id"
// {...e, meta: {system: id}}
...

throw e
}
}
const useCustomersQueries = (systems: System[]) => useQueries({queries: systems.map(s => ({
queryKey: ['customers', s.id],
queryFn: () => getCustomersBySystemId(s.id),
...
}))}).map(...)

async function getCustomersBySystemId(systemId: string) {
try {
// Some axios request
return await api.get(`customers/${id}`)
} catch (e) {
// Potentially set extra meta data on the error, to identify the "id"
// {...e, meta: {system: id}}
...

throw e
}
}
That indeed seems more intuative than jumping through the cache as it can be easily abstracted. Thank you very much for your input. 🙂
optimistic-gold
optimistic-gold3y ago
Yep 👍

Did you find this page helpful?