<script lang="ts">
import { TanStackDevtools } from '@tanstack/svelte-devtools'
import { pacerDevtoolsPlugin } from '@tanstack/svelte-pacer-devtools'
import { createDebouncer } from '@tanstack/svelte-pacer/debouncer'
let instantCount = $state(0)
let debouncedCount = $state(0)
const debouncer = createDebouncer(
(count: number) => {
debouncedCount = count
},
{
key: 'counter',
wait: 800,
enabled: () => instantCount > 2,
},
)
function increment() {
debouncer.maybeExecute(++instantCount)
}
let searchText = $state('')
let debouncedSearchText = $state('')
const setSearchDebouncer = createDebouncer(
(value: string) => {
debouncedSearchText = value
},
{ key: 'search', wait: 500, enabled: () => searchText.length > 2 },
)
function handleSearchChange(event: Event) {
searchText = (event.target as HTMLInputElement).value
setSearchDebouncer.maybeExecute(searchText)
}
let currentValue = $state(50)
let debouncedValue = $state(50)
let instantExecutionCount = $state(0)
let wait = $state(250)
let enabled = $state(true)
const setValueDebouncer = createDebouncer(
(value: number) => {
debouncedValue = value
},
() => ({ key: 'range', wait: wait, enabled: enabled }),
)
function handleRangeChange(event: Event) {
currentValue = (event.target as HTMLInputElement).valueAsNumber
instantExecutionCount++
setValueDebouncer.maybeExecute(currentValue)
}
</script>
<div>
<div>
<h1>TanStack Pacer createDebouncer Example 1</h1>
<table>
<tbody>
<debouncer.Subscribe
selector={(state) => ({
status: state.status,
executionCount: state.executionCount,
})}
>
{#snippet children({ status, executionCount })}
<tr><td>Status:</td><td>{status}</td></tr>
<tr><td>Execution Count:</td><td>{executionCount}</td></tr>
{/snippet}
</debouncer.Subscribe>
<tr><td colspan="2"><hr /></td></tr>
<tr><td>Instant Count:</td><td>{instantCount}</td></tr>
<tr><td>Debounced Count:</td><td>{debouncedCount}</td></tr>
</tbody>
</table>
<div>
<button onclick={increment}>Increment</button><button
onclick={() => debouncer.flush()}
style="margin-left: 10px">Flush</button
>
</div>
<debouncer.Subscribe selector={(state) => state}>
{#snippet children(state)}
<pre style="margin-top: 20px">{JSON.stringify(state, null, 2)}</pre>
{/snippet}
</debouncer.Subscribe>
</div>
<hr />
<div>
<h1>TanStack Pacer createDebouncer Example 2</h1>
<div>
<input
autofocus
type="search"
value={searchText}
oninput={handleSearchChange}
placeholder="Type to search..."
style="width: 100%; margin-bottom: 1rem"
/>
</div>
<table>
<tbody>
<setSearchDebouncer.Subscribe
selector={(state) => ({
isPending: state.isPending,
executionCount: state.executionCount,
})}
>
{#snippet children({ isPending, executionCount })}
<tr><td>Is Pending:</td><td>{isPending.toString()}</td></tr>
<tr><td>Execution Count:</td><td>{executionCount}</td></tr>
{/snippet}
</setSearchDebouncer.Subscribe>
<tr><td colspan="2"><hr /></td></tr>
<tr><td>Instant Search:</td><td>{searchText}</td></tr>
<tr><td>Debounced Search:</td><td>{debouncedSearchText}</td></tr>
</tbody>
</table>
<div><button onclick={() => setSearchDebouncer.flush()}>Flush</button></div>
<setSearchDebouncer.Subscribe selector={(state) => state}>
{#snippet children(state)}
<pre style="margin-top: 20px">{JSON.stringify(state, null, 2)}</pre>
{/snippet}
</setSearchDebouncer.Subscribe>
</div>
<hr />
<div>
<h1>TanStack Pacer createDebouncer Example 3</h1>
<fieldset>
<legend>Reactive options</legend>
<label>
Delay: {wait} ms<input
type="range"
min="0"
max="1500"
step="50"
bind:value={wait}
/>
</label><label
><input type="checkbox" bind:checked={enabled} />Enabled</label
>
<p>
Changing the delay affects the next scheduled call. Disabling cancels
pending work.
</p>
</fieldset>
<div style="margin-bottom: 20px">
<label
>Current Range:<input
type="range"
min="0"
max="100"
value={currentValue}
oninput={handleRangeChange}
style="width: 100%"
/><span>{currentValue}</span>
</label>
</div>
<div style="margin-bottom: 20px">
<label
>Debounced Range (Readonly):<input
type="range"
min="0"
max="100"
value={debouncedValue}
disabled
style="width: 100%"
/><span>{debouncedValue}</span>
</label>
</div>
<table>
<tbody>
<setValueDebouncer.Subscribe
selector={(state) => ({
isPending: state.isPending,
executionCount: state.executionCount,
})}
>
{#snippet children({ isPending, executionCount })}
<tr><td>Is Pending:</td><td>{isPending.toString()}</td></tr>
<tr><td>Instant Executions:</td><td>{instantExecutionCount}</td></tr
>
<tr><td>Debounced Executions:</td><td>{executionCount}</td></tr>
<tr
><td>Saved Executions:</td><td
>{instantExecutionCount - executionCount}</td
></tr
>
<tr
><td>% Reduction:</td><td
>{instantExecutionCount === 0
? '0'
: Math.round(
((instantExecutionCount - executionCount) /
instantExecutionCount) *
100,
)}%</td
></tr
>
{/snippet}
</setValueDebouncer.Subscribe>
</tbody>
</table>
<div style="color: #666; font-size: 0.9em">
<p>Debounced to {wait}ms wait time</p>
</div>
<div><button onclick={() => setValueDebouncer.flush()}>Flush</button></div>
<setValueDebouncer.Subscribe selector={(state) => state}>
{#snippet children(state)}
<pre style="margin-top: 20px">{JSON.stringify(state, null, 2)}</pre>
{/snippet}
</setValueDebouncer.Subscribe>
</div>
</div>
{#if import.meta.env.DEV}
<TanStackDevtools plugins={[pacerDevtoolsPlugin()]} />
{/if}