Reputation: 611
I have two different pages (HTML omitted):
posts/+page.svelte
post/[id]/[title]/+page.svelte
I use TanStack Query for storing data from the API. While I reference Svelte, I also use the documentation for React.js as most syntax seems to be compatible.
In the posts
page, I fetch all posts as an array. It fetches all data, but every time I navigate to this page, an API call is fired. I don't want to make redundant API calls. How can I prevent this behavior?
In the [id]/[title]/
page, I want to fetch post data from the already fetched data from the API, but the post is undefined
. This problem is more serious. How can I log post from cached data?
Here is the simplified code for the two files:
src/routes/posts/+page.svelte
<script lang="ts">
import { onMount } from 'svelte';
import { createQuery } from "@tanstack/svelte-query";
import type { Post } from "$lib/models/Post";
import { fetchPaginatedPosts } from "$lib/posts/fetch-pagination";
import { data } from './store';
// Create the query outside of the render context
const query = createQuery({
queryKey: ["posts"],
queryFn: fetchPaginatedPosts,
initialData: null,
refetchInterval: 360000, // Using the intervalMs from the store if needed
});
// Subscribe to the data store and update it with the query result
onMount(() => {
data.set($query);
});
let posts: Post[] = [];
$: $data = $data || $query.data;
$: {
if ($data && !$data.isLoading && !$data.isError && $data.data) {
posts = $data.data.posts || [];
console.log("call without API", posts);
}
}
</script>
src/routes/post/[id]/[title]/+page.svelte
<script lang="ts">
import { page } from "$app/stores";
import type { Post } from "$lib/models/Post";
import { QueryCache } from "@tanstack/svelte-query";
import { onMount } from "svelte";
const queryCache = new QueryCache()
const query = queryCache.find({ queryKey: ['posts']})
let posts: Post[]
let post: Post
$: id = $page.params.id;
onMount(()=>{
posts = $query.data.posts
post = posts.find(post.id === id)
})
onMount(()=>{
console.log(post)
})
</script>
src/hooks.server.ts
import type { Handle } from '@sveltejs/kit';
import { fetchPaginatedPosts } from '$lib/posts/fetch-pagination';
import { queryClient } from '$lib/posts/queryClient'; // Assuming you have a separate queryClient instance
import { fetchedPosts } from '$lib/posts/store';
import type { Posts } from '$lib/models/Post';
export const handle: Handle = async ({ event, resolve }) => {
if (event.url.pathname.startsWith('/posts')) {
const cachedData = queryClient.getQueryData(['posts']);
if (!cachedData) {
const posts = await fetchPaginatedPosts();
queryClient.setQueryData(['posts'], posts);
fetchedPosts.set(posts)
}else{
fetchedPosts.set(cachedData as unknown as Posts)
}
}
const response = await resolve(event);
return response;
};
Upvotes: 0
Views: 77
Reputation: 279
You can use sveltes Middleware (hooks.server.ts). In the middleware get the data you need, and check if the correct data was retrieved for the page if not run it again.
Upvotes: 0
Reputation: 611
This will solve:
You need to add: queries: {enabled: browser}
src/routes/+layout.svelte
<script lang="ts">
import { browser } from '$app/environment'
import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query'
// add css import if you need
const queryClient = new QueryClient({
defaultOptions: {
queries: {
enabled: browser, // this line
},
},
})
</script>
<QueryClientProvider client={queryClient}>
<slot />
</QueryClientProvider>
Upvotes: 0