useDebouncedRef
Create a Ref<T> whose writes are debounced. Reads are immediate, writes are deferred to a setTimeout followed by a requestAnimationFrame, so consumers always see the most recent committed value while frequent writers (text inputs, scroll handlers, ...) settle without thrashing reactivity.
Demo
- Source ref
- —
- Debounced ref (400ms)
- —
<script setup lang="ts">
import { ref } from 'vue';
import { useDebouncedRef } from '@basmilius/common';
const source = ref('');
const debounced = useDebouncedRef(source, 400);
</script>
<template>
<div class="demo">
<input v-model="source" class="input" placeholder="Type here…"/>
<dl class="readout">
<div>
<dt>Source ref</dt>
<dd>{{ source || '—' }}</dd>
</div>
<div>
<dt>Debounced ref (400ms)</dt>
<dd>{{ debounced || '—' }}</dd>
</div>
</dl>
</div>
</template>
<style scoped>
.demo {
padding: 24px;
border: 1px solid var(--vp-c-border);
border-radius: 12px;
background: var(--vp-c-bg-soft);
}
.input {
width: 100%;
margin-bottom: 16px;
padding: 8px 12px;
border: 1px solid var(--vp-c-border);
border-radius: 8px;
background: var(--vp-c-bg);
font-size: 14px;
color: var(--vp-c-text-1);
}
.readout {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
margin: 0;
}
.readout div {
padding: 12px;
border-radius: 8px;
background: var(--vp-c-bg);
text-align: center;
}
.readout dt {
margin-bottom: 4px;
color: var(--vp-c-text-3);
font-size: 12px;
text-transform: uppercase;
letter-spacing: .04em;
}
.readout dd {
margin: 0;
font-family: var(--vp-font-family-mono);
font-size: 16px;
font-weight: 600;
color: var(--vp-c-brand-1);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>Importing
ts
import { useDebouncedRef } from '@basmilius/common';Usage
vue
<script setup lang="ts">
import { useDebouncedRef } from '@basmilius/common';
const search = useDebouncedRef('', 250);
// Use in a template:
// <input v-model="search"/>
//
// The bound value updates immediately on each keystroke,
// but `search.value` only reflects the latest write after 250 ms.
</script>You can also bind it to an existing ref so the debounced ref tracks the source.
ts
import { ref } from 'vue';
import { useDebouncedRef } from '@basmilius/common';
const source = ref('');
const debounced = useDebouncedRef(source, 200);Passing immediate = true runs the underlying setter once on the leading edge before debouncing the trailing calls.
Type signature
ts
declare function useDebouncedRef<T>(
initialValue: Ref<T> | T,
delay: number,
immediate?: boolean
): Ref<T>;See also
useDebounceduseLoaded— usesuseDebouncedRefinternally to debounce the loading flag