2.0.1 • Published 1 month ago

@svelte-drama/suspense v2.0.1

Weekly downloads
-
License
0BSD
Repository
github
Last release
1 month 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

3 months ago

1.0.0

3 months ago

2.0.1

1 month ago

2.0.0

2 months ago

0.9.0

5 months ago

0.6.6

8 months ago

0.7.0

7 months ago

0.6.5

9 months ago

0.6.3

9 months ago

0.6.4

9 months ago

0.6.2

9 months ago

0.6.1

9 months ago

0.6.0-next.0

10 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

2 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