svelte-stateful-function
v2.0.0
Published
A lightweight utility to wrap functions with reactive status, debounce, and cancellation for Svelte 5
Readme
svelte-stateful-function
A lightweight utility to wrap functions with reactive status, debounce, and cancellation for Svelte 5.
Installation
npm install svelte-stateful-functionUsage
<script lang="ts">
import { stateful } from 'svelte-stateful-function';
let query = $state('')
let results = $state([])
const search = stateful(async (query: string) => {
results = await fetch(`/api/search?q=${encodeURIComponent(query)}`).then(res => res.json());
}, { debounce: 300 });
</script>
<input bind:value={query} oninput={() => search(query)} />
{#if search.busy}
<p>Searching...</p>
{:else}
<p>Type to search</p>
{/if}
<ul>
{#each results as result}
<li>{result}</li>
{/each}
</ul>Reactive State
Each stateful() call returns a function with these reactive properties:
search.pending; // number of functions currently running
search.scheduled; // bool; true if a debounce is currently active
search.busy; // bool; true if pending or scheduled You can react to changes in your component logic:
$effect(() => {
if (search.scheduled) {
console.log('Waiting to search...');
}
});Or in markup:
{#if search.pending}
<p>Searching in progress...</p>
{/if}Options
| Option | Type | Default | Description |
|--------------------|-----------|---------|----------------------------------------------------------|
| debounce | number | — | Debounce delay in ms before executing |
| allowConcurrent | boolean | false | Allow concurrent executions if already running |
API
stateful(fn, options?)
The wrapped function can be either synchronous or asynchronous — both fn() and async fn() are supported.
Returns a callable function with attached metadata:
interface StatefulFunction {
pending: number;
scheduled: boolean;
active: boolean;
cancelScheduled(): void;
}Cancellation
You can cancel a scheduled (when using debounce) call with:
search.cancelScheduled();If the status is 'scheduled', it resets back to 'idle'.
If
debounceis not enabled, callingcancelScheduled()has no effect — since nothing is scheduled to run later.
To prevent scheduled calls from executing after a component is destroyed, you should also manually call cancelScheduled() inside onDestroy():
onDestroy(() => {
search.cancelScheduled();
});License
MIT
