@svelte-drama/suspense v2.0.1
Suspense for Svelte
This is a Svelte component that implements the core idea of React's <Suspense>.
When requesting asynchronous data, a typical pattern is for a parent component to handle all fetching and then push data down to its children. This can become difficult as levels of nesting increase and add unnessecary amounts of complexity. <Suspense> instead lets its children, at an arbitrary nested depth, dictate when they are done loading.
Installation
npm install --save @svelte-drama/suspensesuspend
Child components need to register what data they depend on. suspend returns a function to to handle orchestration between this component and its nearest parent <Suspense> component.
suspend<T extends Promise<any>>(data: T) => TWrap a promise. This returns a promise, allowing it to be used as part of a promise chain. The containing <Suspense> component will display its loading state until the promise is resolved. If the promise is rejected, it will instead show the error state.
suspend<T extends any | undefined>(data: T) => TWrap a model using runes. <Suspense> will consider this resolved as long as data resolves to not undefined. This call should be contained within $effect or $derived in order to update as the underlying data updates.
<Suspense>
<Suspense> extends <svelte:boundary> with a few additional properties:
- loading: If there any pending requests, this slot will be displayed.
- onload: Triggers when all components inside the
<Suspense>block have finished loading.
<script>
import { createSuspense, Suspense } from '@svelte-drama/suspense'
const suspend = createSuspense()
const MyComponent = import('./my-component.svelte').then((m) => m.default)
</script>
<Suspense
onerror={(e) => console.error(e)}
onload={() => console.log('loaded')}
>
{#snippet loading()}
<p>Loading...</p>
{/snippet}
{#snippet failed(error, reset)}
<p>Error: {error?.message || error}</p>
<p>
<button type="button" onclick={reset}> Try Again </button>
</p>
{/snippet}
{#snippet children(suspend)}
<h1>My Component</h1>
{#await suspend(MyComponent) then MyComponent}
<MyComponent />
{/await}
{/snippet}
</Suspense><SuspenseList>
<SuspenseList> orchestrates the loading of all child <Suspense> containers. It guarantees they will load in display order. This is useful to avoid multiple, distracting pop-ins of content or reflow of elements while the user is reading.
- collapse: Boolean. Defaults to
false. Iftrue, only one loading state will be shown among the children. - final: Boolean. Defaults to
false. Iftrue, children will not resuspend if they have been displayed, regardless of the state of previous siblings. - onload: Triggers when all components inside the
<SuspenseList>have finished loading.
<script>
import { Suspense, SuspenseList } from '@svelte-drama/suspense'
import Loading from './loading.svelte'
import Post from './my-component.svelte'
export let posts
</script>
<SuspenseList collapse final>
{#snippet children(loading)}
{#if loading}
<p>Fetching posts...</p>
{/if}
{#each posts as post}
<Suspense>
<Post {post} />
{#snippet loading()}
<Loading />
{/snippet}
</Suspense>
{/each}
{/snippet}
</SuspenseList>Limitations
- Intro transitions will not work as expected on elements inside the default slot. Elements are rendered in a hidden container as soon as possible, which triggers these intro transitions prematurely.
- SSR will only display the loading component. Implementing
<Suspense>during SSR would require Svelte to supportasync/awaitduring SSR.
7 months ago
7 months ago
5 months ago
6 months ago
8 months ago
12 months ago
11 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago