T
TanStack4mo ago
national-gold

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
national-gold
national-goldOP4mo ago
anyone?
like-gold
like-gold4mo ago
Seems like a good fit for cron to call refetch
national-gold
national-goldOP4mo 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
multiple-amethyst
multiple-amethyst4mo 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
national-gold
national-goldOP4mo 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
multiple-amethyst
multiple-amethyst4mo 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
multiple-amethyst
multiple-amethyst4mo 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.
adverse-sapphire
adverse-sapphire4mo 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.
national-gold
national-goldOP4mo 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?