svelte-loadable-store

Svelte Loadable Store

wrappers for vanilla svelte stores to simplify consumption of async apis

Svelte Loadable Store

This library provides wrappers for vanilla svelte stores to simplify consumption of async APIs.

Types

Store value can be in three states: loading, loaded or error. Core types reflect that:

type Loadable<T> = Loading | Loaded<T>;
type Loading = { isLoading: true };
type Loaded<T> = { isLoading: false; value: T } | { isLoading: false; error: any };

writable / readable

writable and readable allow to define stores that are initialized asyncronously, for example:

import { readable } from 'svelte-loadable-store';

const start = performance.now();

const delay = (timeout: number) =>
    new Promise<number>((resolve) => setTimeout(() => resolve(performance.now() - start), timeout));

const store = readable(delay(100), (set) => {
    delay(200).then((value) => set(value));
});

store.subscribe(console.log);

/*
 * prints:
 * { isLoading: true }
 * { isLoading: false, value: 101 }
 * { isLoading: false, value: 201 }
 */

writable is exactly the same, just allows to .set and .update according to the Svelte's contract.

derived

The real power comes with derived stores. Derived function will be executed only after all of the input stores are loaded successfully. You can also derive asyncronously.

import { writable, derived } from 'svelte-loadable-store';

const start = performance.now();

const delay = (timeout: number) =>
    new Promise<number>((resolve) => setTimeout(() => resolve(performance.now() - start), timeout));

const first = writable(delay(100));
const second = writable(delay(200));
const third = derived([first, second], async ([first, second]) => first + second);

first.subscribe((v) => console.log('first', v));
second.subscribe((v) => console.log('second', v));
third.subscribe((v) => console.log('third', v));

/*
 * prints:
 * first { isLoading: true }
 * second { isLoading: true }
 * third { isLoading: true }
 * first { isLoading: false, value: 101 }
 * second { isLoading: false, value: 201 }
 * third { isLoading: false, value: 302 }
 */

error handling

Library exposes a few handy functions to use when working with store values, for example:

<script lang="ts">
    import { writable, derived, Loaded } from 'svelte-loadable-store'

    const fetchData = (): Promise<Data> => fetch('https://api.example.com/data').then(response => response.json())

    const data = writable(fetchData)
</script>

{#if $data.isLoading}
    loading..
{:else Loaded.isError($data)}
    error: {$data.error}
{:else}
    data: {$data.value}
{/if}

promisify

A util funciton that converts a store into promise that will resolve with the first loaded value.

import { readable, promisify } from 'svelte-loadable-store';

const delay = (timeout: number) =>
    new Promise<number>((resolve) => setTimeout(() => resolve(performance.now() - start), timeout));

const store = readable(delay(100));

promisify(store).then(console.log);

/*
 * prints:
 * 101
 */

Acknowledgement

This library is inspired by @square/svelte-store. I have been using it myself before writing this one, but found it having quite a complex interface and faced some issues.

Inspiration for type definitions comes from this nanostores issue.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Top categories

Loading Svelte Themes