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;
};
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.