T
TanStack3y ago
deep-jade

Is there any sane way to do conditional dependent requests?

I have a series of requests that I want to call conditionally based on data of previous requests and enrich payload of the first one With promises I would write it like that
const fooData = await getFoo();

if (fooData.needsBar) {
const barData = await getBar();
enrichFooWithBar(fooData, barData);

if (barData.needsBaz) {
const bazData = await getBaz();
enrichFooWithBaz(fooData, bazData);
}
}

return fooData;
const fooData = await getFoo();

if (fooData.needsBar) {
const barData = await getBar();
enrichFooWithBar(fooData, barData);

if (barData.needsBaz) {
const bazData = await getBaz();
enrichFooWithBaz(fooData, bazData);
}
}

return fooData;
But with hooks this code becomes pretty ugly..
const fooQuery = useQuery(['foo'], () => getFoo());

const barIsEnabled = fooQuery.data?.needsBar ?? false;
const barQuery = useQuery(['bar'], () => getBar(), { enabled: barIsEnabled });

const bazIsEnabled = barQuery.data?.needsBaz ?? false;
const bazQuery = useQuery(['baz'], () => getBaz(), { enabled: bazIsEnabled });

const data = (() => {
const fooData = fooQuery.data;

if (!fooData) return undefined;

if (barQuery.data) {
enrichFooWithBar(fooData, barQuery.data);

if (bazQuery.data) {
enrichFooWithBaz(fooData, bazQuery.data);
}
}

return fooData;
})();
const isLoading = fooQuery.isLoading || barQuery.isInitialLoading || bazQuery.isInitialLoading;

return { data, isLoading };
const fooQuery = useQuery(['foo'], () => getFoo());

const barIsEnabled = fooQuery.data?.needsBar ?? false;
const barQuery = useQuery(['bar'], () => getBar(), { enabled: barIsEnabled });

const bazIsEnabled = barQuery.data?.needsBaz ?? false;
const bazQuery = useQuery(['baz'], () => getBaz(), { enabled: bazIsEnabled });

const data = (() => {
const fooData = fooQuery.data;

if (!fooData) return undefined;

if (barQuery.data) {
enrichFooWithBar(fooData, barQuery.data);

if (bazQuery.data) {
enrichFooWithBaz(fooData, bazQuery.data);
}
}

return fooData;
})();
const isLoading = fooQuery.isLoading || barQuery.isInitialLoading || bazQuery.isInitialLoading;

return { data, isLoading };
Now I have to manually merge all fields like isLoading, isError, status etc into a single object at the end of this custom hook, and also manage optionality, because all data fields become optional Is there any sane way to do this kind of logic? Or maybe I'm missing something?
3 Replies
deep-jade
deep-jadeOP3y ago
Also there are two important things: - we need to get cached data of all requests in case we have it (so we can't just do a single useQuery with async function I described earlier) - we need to redo the whole chain of requests in case getFoo result gets invalidated (so we can't do queryClient.fetchQuery too)
other-emerald
other-emerald2y ago
@temoncher Did you ever find a sane solution?
deep-jade
deep-jadeOP2y ago
Sadly, the best I could do is to use queryClient.fetchQuery instead of actual requests and handle invalidation manually Also you can come up with custom utility that combines query results, but I thought that it will look no better than enabled

Did you find this page helpful?