T
TanStack2mo ago
deep-jade

Refetch at every X seconds

Hey everyone! I have a question about dynamic refetchInterval behavior. I'm working with a query that should refetch every 60 seconds, but I need it to sync with an external schedule. Use case: Users can land on the page at any time, but data updates happen on a fixed 60-second server schedule (e.g., at :00, :01, :02 of each minute). If a user arrives at :40, I want the first refetch to happen in 20 seconds (to sync with the :00 mark), then continue every 60 seconds after that. What's the best way to handle this dynamic interval where the first refetch has a different delay than subsequent ones? I've considered: - Using refetchInterval as a function, but it seems to apply the same logic to all intervals - Manual refetch() calls with useInterval, but wondering if there's a cleaner TanStack Query way - Setting up an initial timeout, then switching to refetchInterval Any suggestions for the most tanstack way to handle this?
9 Replies
deep-jade
deep-jadeOP2mo ago
anyone?
fair-rose
fair-rose2mo ago
Seems like a good fit for cron to call refetch
deep-jade
deep-jadeOP2mo ago
Hmm not sure if i need a cron here, on component mount we receive that timing, so we know exact time left, if user arrives before standard schedule (let's say refetch needs to happen in 20s) we can pass that info
exotic-emerald
exotic-emerald2mo ago
const {
data: users,
} = useQuery({
queryKey: ['users'],
queryFn: async (): Promise<{ data: any, status: "success" | "waiting" }> => {
const existingData: { data: any, status: "success" | "waiting" } | undefined = queryClient.getQueryData(['users']);
const isExistingDataFetched = existingData && existingData.status === "success";
if (!isExistingDataFetched && new Date().getSeconds() > 3) {
return {
data: undefined,
status: "waiting"
};
}
const data = await fetch('https://jsonplaceholder.typicode.com/users')
.then((res) => res.json())
return {
data: data,
status: "success"
};
},
refetchInterval: (query) => {
if (!query.state.data || query.state.data.status === "waiting") {
return 1000;
}
return 1000 * 60;
}
});
const {
data: users,
} = useQuery({
queryKey: ['users'],
queryFn: async (): Promise<{ data: any, status: "success" | "waiting" }> => {
const existingData: { data: any, status: "success" | "waiting" } | undefined = queryClient.getQueryData(['users']);
const isExistingDataFetched = existingData && existingData.status === "success";
if (!isExistingDataFetched && new Date().getSeconds() > 3) {
return {
data: undefined,
status: "waiting"
};
}
const data = await fetch('https://jsonplaceholder.typicode.com/users')
.then((res) => res.json())
return {
data: data,
status: "success"
};
},
refetchInterval: (query) => {
if (!query.state.data || query.state.data.status === "waiting") {
return 1000;
}
return 1000 * 60;
}
});
This is not clean code, but just an idea. Bit of a creative one lol
deep-jade
deep-jadeOP2mo ago
Oh sorry, forgot to mention this, i'm using a wagmi package and it's hook useReadContract which uses tanstack under the hood - https://wagmi.sh/react/api/hooks/useReadContract#query and wagmi does not support passing all tanstack params, in this case queryFn is not supported as they are used internally
exotic-emerald
exotic-emerald2mo ago
Oh well that's unfortunate.. then yea the only thing I can think of is using enabled with some ugly setInterval that marks that as true when you want to start. Maybe someone else has a better idea
conscious-sapphire
conscious-sapphire2mo ago
That's the typical chicken/egg dilemma. refetchInterval is a local variable that starts counting from the moment the query is run. It doesn't know anything about the server time until it gets it somehow from the server. Imagine the user opens a page for the first time and there's no cache for this query, so fetch will happen anyway, and if you include a server refetch time in the response, then you may write some logic to count refetch interval based on that time, but the first fetch must happen anyway.
genetic-orange
genetic-orange2mo ago
You know when the queryFn last ran thanks to dataUpdatedAt. You know the current time. You know when the next fetch should happen. That should be enough to compute the time in a dynamic refetchInterval function.
deep-jade
deep-jadeOP2mo ago
thank you both! i went with a different route for now with manual refetching, however, i would like to check if i can improve with dynamic refetchInterval in some close future

Did you find this page helpful?