# Module: `src/hooks/useDebounce.ts`

> **Source**: `src/hooks/useDebounce.ts` (12 lines)
> **Topo batch**: B1 (leaf)

## Purpose

Generic React hook that delays propagation of a rapidly-changing value to its consumers, used to throttle search inputs against the backend.

## Public interface

```ts
export function useDebounce<T>(value: T, delay: number): T
```

Returns the latest `value` only after `delay` milliseconds have elapsed without any further change. Generic in `T`, so callers can debounce strings, numbers, or any reference value (referential identity matters; see notes).

## Internal logic

`useState<T>(value)` for the debounced output; `useEffect` registers a `setTimeout(setDebounced, delay)` and returns a `clearTimeout` cleanup. The effect re-runs whenever `value` or `delay` changes — each new input value cancels the pending timeout from the previous render and starts a fresh one.

## Dependencies

- **Internal**: none.
- **External**: `react` (`useState`, `useEffect`).

## Consumers (intra-repo)

- `src/features/annotations/MediaList.tsx` — debounces the media-name search input.
- `src/features/dataset/DatasetPage.tsx` — debounces the dataset name-search filter (specified as 400ms in `_docs/ui_design/README.md` §"Dataset Explorer", but the actual delay is set by the caller).

## Data models

None.

## Configuration

None.

## External integrations

None.

## Security

None.

## Tests

None.

## Notes / open questions

- The hook compares values by referential equality (`useEffect` deps array). Passing a fresh object literal each render — e.g. `useDebounce({ q }, 300)` — would re-trigger the timer endlessly. Current callers pass primitives only; safe.
- No "leading edge" / "trailing edge" / "max wait" knobs. Adequate for the two current consumers; if/when richer behaviour is needed, prefer `useDebouncedCallback` from a library over extending this module.
