This library provides wrappers for vanilla svelte stores to simplify consumption of async APIs.
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
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.
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 }
*/
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}
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
*/
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.
This project is licensed under the MIT License. See the LICENSE file for details.