T
TanStack•3y ago
ambitious-aqua

Svelte with tanstack query

I have folder queries/streamQuery.ts in my app. Its content of this file:
export function getStreamsQuery(refetchIntervalS: number = 10) {
return createQuery({
queryKey: ['streams'],
queryFn: async () => {
console.log('fetching streams');
const res = await fetch(`${PUBLIC_API_KEY}/streams`);
const data = await res.json();
return data.map(streamMapper);
},
refetchInterval: refetchIntervalS * 1000
});
}
export function getStreamsQuery(refetchIntervalS: number = 10) {
return createQuery({
queryKey: ['streams'],
queryFn: async () => {
console.log('fetching streams');
const res = await fetch(`${PUBLIC_API_KEY}/streams`);
const data = await res.json();
return data.map(streamMapper);
},
refetchInterval: refetchIntervalS * 1000
});
}
then somewhere in my .svelte files, where I need streams, Im using this like that:
$: streamsQuery = getStreamsQuery($dataRefetchInterval);
$: ({ data, status, isLoading } = $streamsQuery);
$: streamsQuery = getStreamsQuery($dataRefetchInterval);
$: ({ data, status, isLoading } = $streamsQuery);
$dataRefetchInterval is some global store acted like app settings. I would like make my .svelte component not aware, that this stream needs some configuration. From the point of view of .svelte component there is no need to know how to configure this stream. Is there any way to handle this ? As far as I know, I cant use reactive store inside regular .ts function?
8 Replies
absent-sapphire
absent-sapphire•3y ago
v5 beta allows you use stores for your options - you can see the docs here: https://tanstack.com/query/v5/docs/svelte/reactivity
Reactivity | TanStack Query Docs
Svelte uses a compiler to build your code which optimises rendering. By default, components run once, unless they are referenced in your markup. To be able to react to changes in options you need to use stores. In the below example, the refetchInterval option is set from the variable intervalMs, which is bound to the input field. However, as t...
absent-sapphire
absent-sapphire•3y ago
Since you're passing in a store to getStreamsQuery, you could then use a derived store like how I wrote the example on that page
ambitious-aqua
ambitious-aquaOP•3y ago
Thanks! looks nice. I'll test it out. I wonder also if something like this is doable with this approach: I my function getStreamQuery i would like to set reactive global store to listen whether there is isLoading state true. So basically I would like to have one global flag, which is true, whether any isLoading state is true, from any query within the app.
absent-sapphire
absent-sapphire•3y ago
Hmm interesting! Please message in here if you figure out a way to do that 🙂
ambitious-aqua
ambitious-aquaOP•3y ago
sure!
absent-sapphire
absent-sapphire•3y ago
Oh the other thing with this solution - you need getStreamsQuery to accept Readable<number>, so you pass the store directly into the function like getStreamsQuery(dataRefetchInterval)
ambitious-aqua
ambitious-aquaOP•3y ago
@Raytuzio looks like this works fine:
export function getStreamsQuery() {
const query = createQuery(
derived(dataRefetchInterval, ($dataRefetchInterval) => ({
queryKey: ['streams'],
refetchInterval: $dataRefetchInterval * 1000,
queryFn: async () => {
const res = await fetch(`${PUBLIC_API_KEY}/streams`);
const data = await res.json();
return data.map(streamMapper);
}
}))
);

return derived(query, ($query) => {
isAnyStreamLoading.update(() => $query.isLoading || $query.isFetching);

return $query;
});
}
export function getStreamsQuery() {
const query = createQuery(
derived(dataRefetchInterval, ($dataRefetchInterval) => ({
queryKey: ['streams'],
refetchInterval: $dataRefetchInterval * 1000,
queryFn: async () => {
const res = await fetch(`${PUBLIC_API_KEY}/streams`);
const data = await res.json();
return data.map(streamMapper);
}
}))
);

return derived(query, ($query) => {
isAnyStreamLoading.update(() => $query.isLoading || $query.isFetching);

return $query;
});
}
I still don't get it well when should isLoading be triggered and when isFetching 😄 but most important updating global state from this function is achievable quite easy. then in svelte component just:
$: streamsQuery = getStreamsQuery();
$: ({ data, status, isFetching } = $streamsQuery);
$: streamsQuery = getStreamsQuery();
$: ({ data, status, isFetching } = $streamsQuery);
hope I didn't miss anything and there is no memory leak or some unwanted side effects isAnyStreamLoading its just boolean writable store
absent-sapphire
absent-sapphire•3y ago
You should just be able to call const streamsQuery = getStreamsQuery() without the reactive declaration. Also isLoading behaves differently in v5, you can read about it here: https://tanstack.com/query/v5/docs/react/guides/migrating-to-v5#status-loading-has-been-changed-to-status-pending-and-isloading-has-been-changed-to-ispending-and-isinitialloading-has-now-been-renamed-to-isloading
Migrating to TanStack Query v5 | TanStack Query Docs
Breaking Changes v5 is a major version, so there are some breaking changes to be aware of:

Did you find this page helpful?