Components
Loading preview...
A hook that returns a debounced version of the provided value. The debounced value will only update after the specified delay has passed without any new changes to the original value.
npx shadcn@latest add https://21st.dev/r/serafimcloud/use-debounce"use client";
import { useState, useEffect } from 'react';
import { useDebounce } from '@/components/hooks/use-debounce';
import { Input } from "@/components/ui/input";
// Simple Input Demo
export function DebounceInputDemo() {
const [inputValue, setInputValue] = useState('');
const debouncedValue = useDebounce(inputValue, 500);
const [apiResult, setApiResult] = useState('');
useEffect(() => {
// Имитация API запроса
if (debouncedValue) {
setApiResult(`Making API call with: ${debouncedValue}`);
}
}, [debouncedValue]);
return (
<div className="flex flex-col gap-4 w-[300px]">
<div className="space-y-2">
<p className="text-sm text-muted-foreground">
Type something to see debounce in action
</p>
<Input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="Start typing..."
/>
</div>
<div className="space-y-2">
<p className="text-sm font-medium">Current value:</p>
<p className="text-sm text-muted-foreground">{inputValue}</p>
</div>
<div className="space-y-2">
<p className="text-sm font-medium">Debounced value:</p>
<p className="text-sm text-muted-foreground">{debouncedValue}</p>
</div>
<div className="space-y-2">
<p className="text-sm font-medium">API Response:</p>
<p className="text-sm text-muted-foreground">{apiResult}</p>
</div>
</div>
);
}
// Search Demo
export function DebounceSearchDemo() {
const [search, setSearch] = useState('');
const debouncedSearch = useDebounce(search, 500);
const [results, setResults] = useState<string[]>([]);
const [isSearching, setIsSearching] = useState(false);
// Имитация поиска
useEffect(() => {
if (debouncedSearch) {
setIsSearching(true);
// Имитация API запроса
setTimeout(() => {
setResults([
`Result 1 for "${debouncedSearch}"`,
`Result 2 for "${debouncedSearch}"`,
`Result 3 for "${debouncedSearch}"`,
]);
setIsSearching(false);
}, 1000);
} else {
setResults([]);
}
}, [debouncedSearch]);
return (
<div className="flex flex-col gap-4 w-[300px]">
<div className="space-y-2">
<p className="text-sm text-muted-foreground">
Search with debounce
</p>
<Input
type="search"
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="Search..."
/>
</div>
<div className="space-y-2">
{isSearching ? (
<p className="text-sm">Searching...</p>
) : (
results.map((result, index) => (
<p key={index} className="text-sm">
{result}
</p>
))
)}
</div>
</div>
);
}
// Counter Demo
export function DebounceCounterDemo() {
const [count, setCount] = useState(0);
const debouncedCount = useDebounce(count, 1000);
const [savedCounts, setSavedCounts] = useState<number[]>([]);
useEffect(() => {
// Сохраняем значение только когда debouncedCount изменился
if (debouncedCount > 0) {
setSavedCounts(prev => [...prev, debouncedCount]);
}
}, [debouncedCount]);
return (
<div className="flex flex-col gap-4 w-[300px]">
<div className="space-y-2">
<p className="text-sm text-muted-foreground">
Click rapidly to see debounce effect
</p>
<Button
onClick={() => setCount(c => c + 1)}
className="w-full"
>
Increment: {count}
</Button>
</div>
<div className="space-y-2">
<p className="text-sm font-medium">Debounced count:</p>
<p className="text-sm text-muted-foreground">{debouncedCount}</p>
</div>
<div className="space-y-2">
<p className="text-sm font-medium">Saved counts:</p>
<div className="flex flex-wrap gap-2">
{savedCounts.map((savedCount, index) => (
<span
key={index}
className="text-sm bg-muted px-2 py-1 rounded"
>
{savedCount}
</span>
))}
</div>
</div>
</div>
);
}