Reputation: 611
I'm working on a SvelteKit application where I need to fetch a list of posts data and avoid redundant API calls.
Route: all-posts/+page.svelte
fetchAllPostsData()
Route: post/[id]/[title]/+page.svelte
fetchPostDataById(id)
The current implementation results in fetchAllPostsData()
being called, then fetchPostDataById(id)
being called again, which is inefficient. Here's the relevant code:
all-posts/+page.svelte
:
<script>
import { onMount } from 'svelte';
import { fetchAllPostsData } from './fetch-post-data';
let postsDataArr = [];
onMount(async () => {
postsDataArr = await fetchAllPostsData();
});
</script>
<section>
<ul>
{#each postsDataArr as post}
<li><a href={`/post/${post.id}/${post.title.replace(/[\s ]/g, '-')}`}>{post.title}</a></li>
{/each}
</ul>
</section>
post/[id]/[title]/+page.svelte
:
<script>
import { onMount } from 'svelte';
import { page } from '$app/stores';
import { fetchPostDataById } from '../fetch-post-data';
let id;
/**
* @type {any}
*/
let data;
$: id = $page.params.id;
onMount(async () => {
data = await fetchPostDataById(id);
});
</script>
<section>
{#if data}
<div>
<div>{@html data.html}</div>
</div>
{/if}
</section>
Additional Context:
I do not want to remove the fetchPostDataById(id)
functionality entirely, as it is essential for cases where users share a direct link to a post. In such scenarios, the post link should fetch the post data by ID to ensure the correct data is displayed even if the user accesses the post directly via URL.
Question:
How can I refactor my code to avoid calling the API twice? I want to fetch the list of posts once and use that data in both routes without redundant fetches.
Now I am using TanStack Query in Svelte instead of calling an API directly each time. See more on the official doc
<script lang="ts">
import { createQuery } from '@tanstack/svelte-query';
// Define the options for the fetch request
const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({"limit":100})
};
// Fetch function to get paginated posts
const fetchPaginatedPosts = async () => {
try {
const response = await fetch('http://localhost:4000/get-paginated-posts', options);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const res = await response.json()
console.log(res)
/*
res = {
"posts": [
{
"id": "667776bcc5d22d6226f7647b",
"description": "Hello, this is me!",
"title": "My page is here!",
"update_count": 0,
"updated_at": "2024-06-23T10:13:32.190+00:00"
"created_at": "2024-06-23T10:13:32.190+00:00",
"created_by": "666ff11d406248baf2e87df4",
} ,{...}
],
"nextToken": "667776bcc5d22d6226f7647b"
}
*/
return res;
} catch (error) {
console.error(error);
throw error;
}
};
// Create the query
const query = createQuery({
queryKey: ['posts'],
queryFn: fetchPaginatedPosts,
initialData: null,
});
// Access and log the posts data
const result = $query.data
console.log({result})
</script>
<!--html omitted-->
Upvotes: 2
Views: 301
Reputation: 9959
This is a little more complex than one might imagine at first. In order to optimize data fetching, you will want to not only avoid duplicate/unnecessary requests (the goal of your question) but also avoid presenting stale data to your users. In short, you will want to implement an efficient caching mechanism for your posts data.
While you could manually craft such a mechanism using Svelte stores, timestamps, etc., Tanstack, the creators of react-query
, have released a query & caching library for Svelte which will handle the complex details of running an efficient cache for you and make your life a lot easier.
Tanstack has also published several usage examples which should be very helpful in implementing your own use case.
In case you still would prefer going the manual route, I think this other SO answer might prove a good beginning point.
Hopefully you'll find this helpful. Good luck!
Upvotes: 1