Svelte Example: Auto Refetching

svelte
<script lang="ts">
  import {
    useQueryClient,
    createQuery,
    createMutation,
  } from '@tanstack/svelte-query'

  let intervalMs = $state(1000)
  let value = $state<string>('')

  const client = useQueryClient()

  const endpoint = '/api/data'

  const todos = createQuery<{ items: string[] }>(() => ({
    queryKey: ['refetch'],
    queryFn: async () => await fetch(endpoint).then((r) => r.json()),
    // Refetch the data every second
    refetchInterval: intervalMs,
  }))

  const addMutation = createMutation(() => ({
    mutationFn: (value: string) =>
      fetch(`${endpoint}?add=${encodeURIComponent(value)}`).then((r) =>
        r.json(),
      ),
    onSuccess: () => client.invalidateQueries({ queryKey: ['refetch'] }),
  }))

  const clearMutation = createMutation(() => ({
    mutationFn: () => fetch(`${endpoint}?clear=1`).then((r) => r.json()),
    onSuccess: () => client.invalidateQueries({ queryKey: ['refetch'] }),
  }))
</script>

<h1>Auto Refetch with stale-time set to {intervalMs}ms</h1>

<p>
  This example is best experienced on your own machine, where you can open
  multiple tabs to the same localhost server and see your changes propagate
  between the two.
</p>

<label>
  Query Interval speed (ms):{' '}
  <div class="flex">
    <input bind:value={intervalMs} type="number" step="100" />{' '}

    <span
      style="display:inline-block; 
          margin-left:.5rem;
          width:.75rem;
          height:.75rem; 
          background: {todos.isFetching ? 'green' : 'transparent'};
          transition: {!todos.isFetching ? 'all .3s ease' : 'none'};
          border-radius: 100%;
          transform: scale(1.5)"
    ></span>
  </div>
</label>
<h2>Todo List</h2>
<form
  onsubmit={(e) => {
    e.preventDefault()
    e.stopPropagation()
    addMutation.mutate(value, {
      onSuccess: () => (value = ''),
    })
  }}
>
  <input placeholder="enter something" bind:value />
</form>

{#if todos.isPending}
  Loading...
{/if}
{#if todos.error}
  An error has occurred:
  {todos.error.message}
{/if}
{#if todos.isSuccess}
  <ul>
    {#each todos.data.items as item}
      <li>{item}</li>
    {/each}
  </ul>
  <div>
    <button onclick={() => clearMutation.mutate(undefined)}> Clear All </button>
  </div>
{/if}

<pre
  class={['updating-text', todos.isFetching && 'on']}
  style="font-weight:700">Background Updating...</pre>

<style>
  li {
    text-align: left;
  }

  .updating-text {
    color: transparent;
    transition: all 0.3s ease;
  }
  .updating-text.on {
    color: green;
    transition: none;
  }
</style>
<script lang="ts">
  import {
    useQueryClient,
    createQuery,
    createMutation,
  } from '@tanstack/svelte-query'

  let intervalMs = $state(1000)
  let value = $state<string>('')

  const client = useQueryClient()

  const endpoint = '/api/data'

  const todos = createQuery<{ items: string[] }>(() => ({
    queryKey: ['refetch'],
    queryFn: async () => await fetch(endpoint).then((r) => r.json()),
    // Refetch the data every second
    refetchInterval: intervalMs,
  }))

  const addMutation = createMutation(() => ({
    mutationFn: (value: string) =>
      fetch(`${endpoint}?add=${encodeURIComponent(value)}`).then((r) =>
        r.json(),
      ),
    onSuccess: () => client.invalidateQueries({ queryKey: ['refetch'] }),
  }))

  const clearMutation = createMutation(() => ({
    mutationFn: () => fetch(`${endpoint}?clear=1`).then((r) => r.json()),
    onSuccess: () => client.invalidateQueries({ queryKey: ['refetch'] }),
  }))
</script>

<h1>Auto Refetch with stale-time set to {intervalMs}ms</h1>

<p>
  This example is best experienced on your own machine, where you can open
  multiple tabs to the same localhost server and see your changes propagate
  between the two.
</p>

<label>
  Query Interval speed (ms):{' '}
  <div class="flex">
    <input bind:value={intervalMs} type="number" step="100" />{' '}

    <span
      style="display:inline-block; 
          margin-left:.5rem;
          width:.75rem;
          height:.75rem; 
          background: {todos.isFetching ? 'green' : 'transparent'};
          transition: {!todos.isFetching ? 'all .3s ease' : 'none'};
          border-radius: 100%;
          transform: scale(1.5)"
    ></span>
  </div>
</label>
<h2>Todo List</h2>
<form
  onsubmit={(e) => {
    e.preventDefault()
    e.stopPropagation()
    addMutation.mutate(value, {
      onSuccess: () => (value = ''),
    })
  }}
>
  <input placeholder="enter something" bind:value />
</form>

{#if todos.isPending}
  Loading...
{/if}
{#if todos.error}
  An error has occurred:
  {todos.error.message}
{/if}
{#if todos.isSuccess}
  <ul>
    {#each todos.data.items as item}
      <li>{item}</li>
    {/each}
  </ul>
  <div>
    <button onclick={() => clearMutation.mutate(undefined)}> Clear All </button>
  </div>
{/if}

<pre
  class={['updating-text', todos.isFetching && 'on']}
  style="font-weight:700">Background Updating...</pre>

<style>
  li {
    text-align: left;
  }

  .updating-text {
    color: transparent;
    transition: all 0.3s ease;
  }
  .updating-text.on {
    color: green;
    transition: none;
  }
</style>