T
TanStack4w ago
equal-aqua

Combined Queries Best Practice

Still struggling with the best way to set this up. I have queries from multiple different accounts but for the same data, and I want to unify them into a collection. This seems the simplest, and works:
const queries = useMemo(() => createQueryDefinitions(accounts), [accountsHash])
const eligibleRolesQuery = useQueries({
queries,
combine: result => {
return {
data: result.flatMap(r => r.data ?? []),
isLoading: result.flatMap(r => r.isLoading),
}
},
})

const collection = useMemo(
() =>
createCollection(
queryCollectionOptions({
queryKey: ['pim', 'eligibleRoles', eligibleRolesQuery.data],
queryFn: async () => eligibleRolesQuery.data,
refetchInterval,
queryClient,
getKey: role => role.id,
})
),
[accountsHash, queryClient]
)
const queries = useMemo(() => createQueryDefinitions(accounts), [accountsHash])
const eligibleRolesQuery = useQueries({
queries,
combine: result => {
return {
data: result.flatMap(r => r.data ?? []),
isLoading: result.flatMap(r => r.isLoading),
}
},
})

const collection = useMemo(
() =>
createCollection(
queryCollectionOptions({
queryKey: ['pim', 'eligibleRoles', eligibleRolesQuery.data],
queryFn: async () => eligibleRolesQuery.data,
refetchInterval,
queryClient,
getKey: role => role.id,
})
),
[accountsHash, queryClient]
)
However it results in a new query each time the source data changes and my devtools is littered with it. I was thinking something where I make the query key just 'pim','eligibleRoles', and whenever the depending queries update their data, to trigger an invalidation on the dependent collection query. Might result in a lot of re-queries but the collection will dedupe those and if data hasn't changed, nothing will trigger at the collection level. Any best practices for this type of situation?
1 Reply
equal-aqua
equal-aquaOP4w ago
I wuld have prevously used onSuccess to invalidate the collection query but looks like that was removed in v5, so what's the alternative? I tried a useEffect to invalidate the query, no luck. I tried to move the "combine" directly into the queryFn but no luck there either.
const queryResults = useQueries({ queries })

const queryKey = useMemo(() => ['pim', 'eligibleRoles'], [])

const collection = useMemo(
() =>
createCollection(
queryCollectionOptions({
queryKey,
queryFn: async () => queryResults.flatMap(q => q.data ?? []),
refetchInterval,
queryClient,
getKey: role => role.id,
})
),
[accountsHash, queryClient, queryKey]
)
const queryResults = useQueries({ queries })

const queryKey = useMemo(() => ['pim', 'eligibleRoles'], [])

const collection = useMemo(
() =>
createCollection(
queryCollectionOptions({
queryKey,
queryFn: async () => queryResults.flatMap(q => q.data ?? []),
refetchInterval,
queryClient,
getKey: role => role.id,
})
),
[accountsHash, queryClient, queryKey]
)
How am I supposed to do this dependent query collection such that it is working on the "fresh" dependent queries but without recreating the collection every time data changes? Looks like the answer is to use GetQueryData
const collection = useMemo(
() =>
createCollection(
queryCollectionOptions({
queryKey,
queryFn: async () => {
const latestResults = queries.map(query => queryClient.getQueryData<RoleSchedule[]>(query.queryKey) ?? [])
return latestResults.flat()
},
refetchInterval,
queryClient,
getKey: role => role.id,
})
),
[accountsHash, queryClient, queryKey, queries]
)
const collection = useMemo(
() =>
createCollection(
queryCollectionOptions({
queryKey,
queryFn: async () => {
const latestResults = queries.map(query => queryClient.getQueryData<RoleSchedule[]>(query.queryKey) ?? [])
return latestResults.flat()
},
refetchInterval,
queryClient,
getKey: role => role.id,
})
),
[accountsHash, queryClient, queryKey, queries]
)

Did you find this page helpful?