Async Fetching in Svelte 5
Jonathan Gamble

Jonathan Gamble @jdgamble555

About: My main job is not in IT, but I do have a CS degree and have been programming for over 20 years (only born in 1984). I hate dealing with Servers, and want Graph Databases to be the new norm.

Location:
Louisiana
Joined:
Feb 9, 2021

Async Fetching in Svelte 5

Publish Date: Nov 15 '24
14 6

When you want to fetch something in Svelte, the recommended method is to put it in the load function.

I wrote an article about async fetching and why this could be important to work outside the load function.

Generally speaking, when SSR is not involved, you have better control of race conditions, error handling, and implementation outside the load function. While I agree in MOST situations you should use the load functions (with SvelteKit), this is not true for ALL situations.

Here is a simple resource function to handle this:

// resource.svelte.ts

export let resource = <T>(
    fn: () => Promise<T>,
    initialValue?: T
) => {

    const _rune = $state<{ value: T | undefined }>({
        value: initialValue
    });

    $effect(() => {
        fn().then((data) => {
            _rune.value = data;
        });
    });

    return _rune;
};
Enter fullscreen mode Exit fullscreen mode

And you would use it like so in your component:

import { resource } from '$lib/resource.svelte';
...
const todo = resource<Todo>(() =>
  fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
    .then((response) => response.json())
);
Enter fullscreen mode Exit fullscreen mode

And show the value with:

{todo.value}
Enter fullscreen mode Exit fullscreen mode

Similar Concepts in Other Frameworks

Now you can easily create a signal from an async resource! I hope something like this can get implemented in Svelte like $resource one day.

Demo: Vercel
Repo: GitHub

J

Update 2/2/25

It is good practice to handle the abort controller, so I added a version for that as well.

export let resource = <T>(
    getter: () => RequestInfo | URL,
    initialValue?: T
) => {

    const _rune = $state<{ value: T | undefined }>({
        value: initialValue
    });

    const controller = new AbortController();
    const { signal } = controller;

    $effect(() => {
        const url = getter();
        fetch(url, { signal })
            .then((response) =>
                response.json()
            )
            .then((data) => {
                _rune.value = data;
            });
        return () => controller.abort();
    });

    return _rune;
};
Enter fullscreen mode Exit fullscreen mode

This assumes you would call it:

const todo = resource<Todo>(() => 
    `https://jsonplaceholder.typicode.com/todos/${id}`
);

Enter fullscreen mode Exit fullscreen mode

There are many things you could do with this, maybe we will see something like this officially in Svelte.

J

Comments 6 total

  • José Pablo Ramírez Vargas
    José Pablo Ramírez VargasNov 15, 2024

    As a correction, the load function and SSR only exist in Sveltekit, so maybe the title should say Sveltekit. Remember that one can do Svelte in non-Sveltekit projects.

  • Mercy
    MercyNov 18, 2024

    Works in both though

  • Mark Stein
    Mark SteinNov 19, 2024

    This is awesome, thanks man

Add comment