2.0.1 • Published 4 months ago

@svelte-drama/suspense v2.0.1

Weekly downloads
-
License
0BSD
Repository
github
Last release
4 months ago

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.

See it in action

Installation

npm install --save @svelte-drama/suspense

suspend

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) => T

Wrap 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) => T

Wrap 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. If true, only one loading state will be shown among the children.
  • final: Boolean. Defaults to false. If true, 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 support async/await during SSR.
1.0.1

5 months ago

1.0.0

5 months ago

2.0.1

4 months ago

2.0.0

5 months ago

0.9.0

7 months ago

0.6.6

10 months ago

0.7.0

10 months ago

0.6.5

11 months ago

0.6.3

11 months ago

0.6.4

11 months ago

0.6.2

11 months ago

0.6.1

11 months ago

0.6.0-next.0

12 months ago

0.5.1

1 year ago

0.4.7

1 year ago

0.4.6

2 years ago

0.4.3

2 years ago

0.4.2

2 years ago

0.4.1

2 years ago

0.4.0

2 years ago

0.3.10

3 years ago

0.3.9

3 years ago

0.3.8

3 years ago

0.3.6

4 years ago

0.3.5

4 years ago

0.3.4

4 years ago

0.3.3

4 years ago

0.3.2

4 years ago

0.3.1

4 years ago

0.3.0

4 years ago