I am facing a situation where I will first use a useQuery to fetch an object, which contains multiple URLs three levels deep. And then, I'll use a useQueries to fetch all those URLs. And example given Dependent Queries cannot handle this situation.
For example:
// Get the users ids
const { data: userIds } = useQuery({
queryKey: ['users'],
queryFn: getUsersData
})
const usersMessages = useQueries({
queries: userIds ?
userIds.map(id => {
return {
queryKey: ['messages', id],
queryFn: () => getMessagesByUsers(id),
};
})
: [],
})
The above code works if userIds
is like:
[ url1, url2, url3, url4 ]
.
However, in my case, the userIds
has the following structure:
[
{'name':'A', 'id': [url1, url2]},
{'name':'B', 'id': [url3, url4]}
]
and my objective is to fetch from all URLs.
I can't change the first query using "select" to change the format of the returned data because I am collaborating with others, and changing that would incur many other refactors.
I tried to first get userIds
, and then decompose it to form a new array that only contains all the URLs, give this new array to the second useQueries
and meanwhile set dependency on !isLoading
of the first query, which does not work. The code enters in to a loop and throw an error "Rendered more hooks than during the previous render".
From the link you provided there is a select
prop so you can manipulate the returned data.
Try something like this
const { data: userIds } = useQuery({
queryKey: ['users'],
queryFn: getUsersData,
select: users => users.reduce((ids, user) => {
user.id.forEach(id => ids.push(id);
return ids;
}, []),
})
This will flatten the id
array in each user into one array
In case you don't want to change the first query, maybe create a new one? Or you could modify the second like this
const usersMessages = useQueries({
queries: userIds ?
userIds.reduce((ids, user) => {
user.id.forEach(id => ids.push(id);
return ids;
}, []).map(id => {
return {
queryKey: ['messages', id],
queryFn: () => getMessagesByUsers(id),
};
})
: [],
})