Initial commit
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
# useDebounceSearch
|
||||
|
||||
Controls a search input with debouncing and a minimum character threshold. Only fires the `onTimeOut` callback after the user stops typing and the query meets the minimum length.
|
||||
|
||||
## Signature
|
||||
|
||||
```ts
|
||||
function useDebounceSearch(params: UseDebounceSearchParams): DebounceSearchController;
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
```ts
|
||||
type UseDebounceSearchParams = {
|
||||
onTimeOut: (query: string) => void;
|
||||
minQueryNumber?: number;
|
||||
initialQuery?: string | null;
|
||||
delay?: number;
|
||||
};
|
||||
```
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
| ---------------- | ------------------------- | ------- | ------------------------------------------------------------ |
|
||||
| `onTimeOut` | `(query: string) => void` | — | Called with the current query after `delay` ms of inactivity |
|
||||
| `minQueryNumber` | `number` | `3` | Minimum characters required before `onTimeOut` is invoked |
|
||||
| `initialQuery` | `string \| null` | `''` | Initial value of the controlled input |
|
||||
| `delay` | `number` | `800` | Debounce delay in milliseconds |
|
||||
|
||||
### Returns
|
||||
|
||||
```ts
|
||||
type DebounceSearchController = {
|
||||
query: string;
|
||||
handleChange: (value: string) => void;
|
||||
};
|
||||
```
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------------- | ------------------------- | -------------------------------------- |
|
||||
| `query` | `string` | Current value of the search input |
|
||||
| `handleChange` | `(value: string) => void` | Pass to the input's `onChange` handler |
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
function SearchBox() {
|
||||
const { query, handleChange } = useDebounceSearch({
|
||||
onTimeOut: (q) => fetchResults(q),
|
||||
minQueryNumber: 2,
|
||||
delay: 500,
|
||||
});
|
||||
|
||||
return <input value={query} onChange={(e) => handleChange(e.target.value)} placeholder="Search…" />;
|
||||
}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Queries shorter than `minQueryNumber` (but not empty) cancel any pending debounced call.
|
||||
- Uses `throttle-debounce` under the hood via a stable `useRef` to avoid resetting the timer on each render.
|
||||
- Client-only (`'use client'`).
|
||||
@@ -0,0 +1 @@
|
||||
export * from './useDebounceSearch';
|
||||
@@ -0,0 +1,38 @@
|
||||
'use client';
|
||||
|
||||
import { useRef, useState } from 'react';
|
||||
import { debounce } from 'throttle-debounce';
|
||||
|
||||
export type UseDebounceSearchParams = {
|
||||
onTimeOut: (query: string) => void;
|
||||
minQueryNumber?: number;
|
||||
initialQuery?: string | null;
|
||||
delay?: number;
|
||||
};
|
||||
|
||||
export type DebounceSearchController = {
|
||||
query: string;
|
||||
handleChange: (value: string) => void;
|
||||
};
|
||||
|
||||
export const useDebounceSearch = (params: UseDebounceSearchParams): DebounceSearchController => {
|
||||
const { onTimeOut, minQueryNumber = 3, delay = 800, initialQuery } = params;
|
||||
|
||||
const [query, setQuery] = useState(initialQuery ?? '');
|
||||
|
||||
const throttled = useRef(debounce(delay, (callback: () => void) => callback()));
|
||||
const bind = (value: string) => throttled.current(onTimeOut.bind(null, value));
|
||||
const unbind = () => throttled.current(() => {});
|
||||
|
||||
const handleChange = (value: string) => {
|
||||
setQuery(value);
|
||||
|
||||
if (value.length < minQueryNumber && value.length !== 0) {
|
||||
return unbind();
|
||||
}
|
||||
|
||||
bind(value);
|
||||
};
|
||||
|
||||
return { query, handleChange };
|
||||
};
|
||||
Reference in New Issue
Block a user