SSWR (Svelte Stale While Revalidate)

repository·master·Indexed 43 days ago

https://github.com/consoletvs/sswr

A lightweight (2KB) data-fetching library for Svelte implementing the SWR caching strategy. Version 2.1.0 provides reactive stores for data, errors, and loading states, featuring request deduplication, dependent fetching, and manual mutation via the useSWR hook. It supports global configuration through createSWR and createDefaultSWR, and integrates with SvelteKit SSR by utilizing initialData and disabling revalidateOnStart.

Tokens
4.1K
Snippets
14
Records
15
Agent score
5%

What's inside SSWR

  1. How dependent fetching works

    master

    You can perform dependent fetching by passing a function as the key to useSWR. When the dependency (e.g., a previous request's data) is not yet available, the function can throw an error or return a value that causes the hook to wait. Once the dependency is resolved, the function returns the new key, and the hook fetches the dependent data.

    Example:

    <script>
      import { useSWR } from "sswr";
    
      // Primary request
      const { data: post } = useSWR("https://jsonplaceholder.typicode.com/posts/1");
    
      // Dependent request: the key is a function that depends on $post
      $: ({ data: user } = useSWR(
        () => `https://jsonplaceholder.typicode.com/users/${$post.userId}`
      ));
    </script>
    
    {#if $post}
      <div>{$post.title}</div>
    {/if}
    {#if $user}
      <div>{$user.name}</div>
    {/if}
    <script>
      import { useSWR } from "sswr";
    
      const { data: post } = useSWR("https://jsonplaceholder.typicode.com/posts/1");
      $: ({ data: user } = useSWR(
        () => `https://jsonplaceholder.typicode.com/users/${$post.userId}`
      ));
    </script>
    
    {#if $post}
      <div>{$post.title}</div>
    {/if}
    {#if $user}
      <div>{$user.name}</div>
    {/if}
  2. Get started with useSWR

    master

    The useSWR hook is the primary way to fetch data. Pass a key (usually a URL string) to the hook. The hook returns a Svelte store that you can subscribe to using the $ prefix. By default, it uses a standard fetch implementation to retrieve JSON data.

    <script>
      import { useSWR } from "sswr";
      // The key is passed to the fetcher function
      const { data: posts } = useSWR("https://jsonplaceholder.typicode.com/posts");
    </script>
    
    {#if $posts}
      {#each $posts as post (post.id)}
        <h1>{post.title}</h1>
        <p>{post.body}</p>
      {/each}
    {/if}
  3. Use SSWR with SvelteKit SSR

    master

    You can combine SvelteKit's server-side rendering (SSR) with SSWR's client-side live updating. This pattern involves fetching data in the SvelteKit load function and passing it to the component as initialData.

    To prevent the client from immediately re-fetching the data that was just provided by the server, set revalidateOnStart: false in the useSWR configuration.

    Implementation Pattern

    1. Use a context="module" script to define the SvelteKit load function.
    2. Fetch data using the SvelteKit fetch API.
    3. Return the data in the props object.
    4. In the component script, receive the initialData prop.
    5. Initialize useSWR with the initialData and revalidateOnStart: false.
    <script lang="ts" context="module">
      import type { Load } from '@sveltejs/kit';
    
      const url = 'https://jsonplaceholder.typicode.com/posts';
    
      export const load: Load = async ({ fetch }) => {
        const response = await fetch(url);
    
        return {
          props: {
            initialData: await response.json()
          }
        };
      };
    </script>
    
    <script lang="ts">
      import { useSWR } from 'sswr';
    
      interface Post {
        id: number;
        title: string;
        body: string;
      }
    
      export let initialData: Post[];
    
      const { data: posts } = useSWR<Post[]>(url, {
        initialData,
        revalidateOnStart: false
      });
    </script>
    
    {#if $posts}
      {#each $posts as post (post.id)}
        <h1>{post.title}</h1>
        <p>{post.body}</p>
      {/each}
    {/if}
  4. Handle errors in SSWR

    master

    Errors are handled via the error store returned by the useSWR hook. If a request fails, the error store will contain the error object, and the data store will typically be undefined.

    <script>
      import { useSWR } from 'sswr'
      const { data: posts, error } = useSWR('https://jsonplaceholder.typicode.com/posts')
    </script>
    
    {#if $error}
      <div>There was an error</div>
    {:else if $posts}
     {#each $posts as post (post.id)}
        <h1>{post.title}</h1>
     {/each}
    {/if}
  5. Initialize and configure the default SWR instance

    master

    SSWR provides a default exported instance swr that can be used globally. You can customize this global instance using createDefaultSWR.

    import { createDefaultSWR } from 'sswr';
    
    // This sets the global 'swr' instance with custom options
    const swr = createDefaultSWR({ 
      // SWROptions configuration
    });
  6. Clear the cache using the global clear function

    master

    You can invalidate specific keys or clear the entire cache using the global clear function imported from sswr. If no keys are provided, the entire cache is cleared.

    Signature

    function clear(keys, options): void

    Parameters

    • keys: A single key or an array of keys to delete. If undefined, all keys are cleared.
    • options: A partial object containing:
      • broadcast: boolean: If true, the cache change is broadcast to subscribed handlers, notifying them that the value now resolves to undefined.
    import { clear } from 'sswr'
    
    // Clear everything
    clear();
    
    // Clear specific keys
    clear(['key1', 'key2'], { broadcast: true });
  7. Re-validate data on demand

    master

    You can trigger a revalidation (refetch) manually using either a global function or a local function returned by the hook.

    Using the global revalidate function

    Import revalidate from sswr and provide the resolved key.

    Signature: function revalidate(key, options): void

    Parameters:

    • key: The resolved string key to re-validate.
    • options:
      • force: boolean (default false). If true, ignores dedupingInterval and forces a fetch.

    Using the local revalidate function

    If you destructure revalidate from useSWR, it is already bound to the specific key.

    Signature: function revalidate(options): void

    Example:

    <script>
      import { useSWR } from 'sswr'
      const { data: post, revalidate } = useSWR('https://jsonplaceholder.typicode.com/posts/1')
    </script>
    
    {#if $post}
      <div>{$post.title}</div>
      <button on:click={() => revalidate()}>Revalidate</button>
    {/if}
  8. Mutate data on demand

    master

    Mutation allows you to manually update the local cache. You can use a global mutate function or a local one returned by useSWR.

    Using the global mutate function

    Signature: function mutate(key, value, options): void

    Parameters:

    • key: The resolved string key.
    • value: The new value, or a function (currentValue) => newValue.
    • options:
      • revalidate: boolean (default true). Whether to trigger a revalidation after mutation.
      • revalidateOptions: Partial<SWRRevalidateOptions>. Options passed to the subsequent revalidation.

    Using the local mutate function

    Signature: function mutate(value, options): void

    Example (Optimistic UI):

    <script>
      import { useSWR } from 'sswr'
      const { data: post, mutate } = useSWR('https://jsonplaceholder.typicode.com/posts/1')
    </script>
    
    {#if $post}
      <div>{$post.title}</div>
      <!-- Mutate using a function to update only the title -->
      <button on:click={() => mutate((state) => ({ ...state, title: 'Sample' }), { revalidate: false })}>
        Mutate only title
      </button>
      <!-- Mutate using a static object -->
      <button on:click={() => mutate({ title: 'Sample' }, { revalidate: false })}>
        Leave only title
      </button>
    {/if}
    <script>
      import { useSWR } from 'sswr'
      const { data: post, mutate } = useSWR('https://jsonplaceholder.typicode.com/posts/1')
    </script>
    
    {#if $post}
      <div>{$post.title}</div>
      <button on:click={() => mutate((state) => ({ ...state, title: 'Sample' }), { revalidate: false })}>
        Mutate only title
      </button>
      <button on:click={() => mutate({ title: 'Sample' }, { revalidate: false })}>
        Leave only title
      </button>
    {/if}
  9. Configure SSWR globally

    master

    To avoid passing the same options to every useSWR call, you can configure global options. You can either manually create an instance or replace the default instance used by the exported APIs (recommended).

    Signatures:

    • function createSWR(options): VSWR
    • function createDefaultSWR(options): VSWR

    The options object passed to these functions accepts the same properties as the options argument in useSWR.

  10. Use the useSWR hook

    master

    The useSWR hook implements the stale-while-revalidate strategy. It returns several reactive stores to manage the lifecycle of a request.

    Signature: function useSWR(key, options): SWRResponse

    Destructured Return Values:

    • data: Writable<D | undefined>: The data from the fetcher. undefined if loading or if an error occurred.
    • error: Writable<E | undefined>: The error object if the request failed.
    • mutate: (value, options) => void: A local alias to mutate the data for this specific key.
    • revalidate: (options) => void: A local alias to trigger a revalidation for this specific key.
    • clear: (options) => void: Clears the current key's data from the cache.
    • isLoading: Readable<boolean>: true if the request is in progress.
    • isValid: Readable<boolean>: true if there is no associated error.

    Parameters:

    • key: A string or a function. If a function is provided, it can be used for dependent fetching.
    • options: An optional configuration object:
      • cache: SWRCache instance (defaults to new DefaultCache()).
      • errors: EventTarget for error dispatching.
      • fetcher: (key) => Promise<any> function to retrieve data (defaults to a JSON fetch call).
      • initialData: Initial data to use instead of undefined.
      • revalidateOnStart: boolean (default true). Revalidates on mount.
      • dedupingInterval: number (default 2000). Prevents duplicate requests within this window.
      • revalidateOnFocus: boolean (default true). Revalidates when window regains focus.
      • focusThrottleInterval: number (default 5000). Throttles focus revalidation.
      • revalidateOnReconnect: boolean (default true). Revalidates when network status changes.
    const { data, error, mutate, revalidate } = useSWR(key, options);
  11. Clear cached data for a specific hook

    master

    When using the useSWR hook, you can destructure a clear function that is already bound to that specific hook's key. This allows you to clear the data for that specific request on demand without manually passing the key.

    Signature

    function clear(options): void

    Parameters

    • options: Same as the global clear function (supports broadcast: boolean).
    <script>
      import { useSWR } from 'sswr'
    
      const { data: post, clear } = useSWR('https://jsonplaceholder.typicode.com/posts/1')
    </script>
    
    {#if $post}
      <div>{$post.title}</div>
      <button on:click={() => clear()}>
        Clear cached data
      </button>
    {/if}