Limiting Parallelism for useQueries #4943
-
The ScenarioWe've got a bar chart where each day fetches data from a unique api/database endpoint. When the user selects a range for 365+ days, it takes exponentially longer to load. The ProblemUnder the hood, we're using My ResearchI've gone spelunking for answers on "debouncing" and "throttling" TanStack Query, and all of the existing threads are concerned with React Query does offer Feature Request?I would prefer a solution that allows for a Workaround IdeasI've so far only thought of a couple workarounds that would only allow for 1 query to run at a time. In both cases, I'd use 1 running query to increment an index upon
|
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 4 replies
-
Hi 👋 It sounds like the issue may stem from an API design flaw in my opinion. It seems like you're making N requests (N being the number of days in the range) for a given date range when I'd imagine this could be done in a single request that specifies the interesting date range. Is this something you could consider? I agree with your sentiment that rate limiting is the responsibility of the API. Also, remember that people can make requests to your API without using your client/application. Does this help? 🙂 |
Beta Was this translation helpful? Give feedback.
-
I found a solution that works for the complex application I work on, and I want to make sure I share what I found for the next person, especially since I didn't find anyone else talking about how to do this sort of thing. My project is using React, but I think these should be usable across frameworks. Here's a list of what you'll need installed:
A time-paginated useQueries functionThis makes use of a function import { useQueries } from 'react-query';
function dateIsToday(dateParameter) {
var today = new Date();
return dateParameter.getDate() === today.getDate() &&
dateParameter.getMonth() === today.getMonth() &&
dateParameter.getFullYear() === today.getFullYear();
}
function getDaysArray(start, end) {
for (var arr = [], dt = new Date(start); dt <= new Date(end); dt.setDate(dt.getDate() + 1)) {
arr.push(new Date(dt));
}
return arr;
}
export default function useChartData({ start_time, end_time }) {
let dates = getDaysArray(start_time, end_time);
return useQueries(
dates.map(date => ({
queryKey: [
'chart',
{
query: {
start_time: new Date(date.setHours(0, 0, 0, 0)).toISOString(),
end_time: new Date(date.setHours(23, 59, 59, 999)).toISOString(),
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
},
},
],
queryFn: fetchChartData,
enabled: start_time !== undefined && end_time !== undefined,
refetchOnWindowFocus: dateIsToday(date),
staleTime: dateIsToday(date) ? 3 * 60 * 1000 : Infinity,
})),
); A fetch function that uses a mutex and query cancellationThe best solution we came up with lives in the
import { Mutex } from 'async-mutex';
const chartMutex = new Mutex();
export async function fetchChartData({ queryKey, signal }) {
const [, { query }] = queryKey;
const queryString = new URLSearchParams(query).toString();
const data = await chartMutex.runExclusive(async () => {
return await fetch(`/api/d2c/tenant/${tenant_id}/task-histogram?${queryString}`, { signal });
});
if (!data.ok) {
throw new Error('Failed to get histogram data', data.statusText, data.status);
}
const response = await data.json();
return response;
} |
Beta Was this translation helpful? Give feedback.
-
Just adding this here in case someone else needs it in the future, I had a very similar problem but still wanted a few requests to be in flight at the same time (rather than one at a time), so came up with this hook:
Usage:
|
Beta Was this translation helpful? Give feedback.
I found a solution that works for the complex application I work on, and I want to make sure I share what I found for the next person, especially since I didn't find anyone else talking about how to do this sort of thing. My project is using React, but I think these should be usable across frameworks.
Here's a list of what you'll need installed:
A time-paginated useQueries function
This makes use of a function
getDaysArray
to split up astart_time
andend_time
into a list ofdates
.useQueries
uses thedates
mapped out so that eachqueryKey
uses the start and end of each day. The timezone is included in the query to ensure timezone differences obtain a uniqueq…