useThrottleState provides state with a throttled setter (leading + trailing).
- First call after a quiet period updates the state immediately (leading).
- Subsequent calls within the
delayMswindow are coalesced into a single update at the end of the window with the latest value (trailing). - The setter reference is stable between renders (convenient for deps and event subscriptions).
- Any pending trailing update is cleared on unmount.
- Changing
delayMsdoes not affect an already scheduled trailing update; the new interval applies to subsequent setter calls.
// Variant 1: delay only, initial state is undefined
function useThrottleState<State = undefined>(
delayMs: number,
): UseThrottleStateReturn<State | undefined>;
// Variant 2: explicit initial value
function useThrottleState<State>(
initialState: State | (() => State),
delayMs: number,
): UseThrottleStateReturn<State>;Parameters
initialState— initial value or lazy initializer (optional).delayMs— throttling window in milliseconds.
Returns
- Tuple
[state, setThrottleState]:state— current value;setThrottleState(next)— throttled setter (stable reference), accepts a value or a functional updater.
import { useThrottleState } from '@webeach/react-hooks/useThrottleState';
export function SearchBox() {
const [query, setQuery] = useThrottleState('', 300);
return (
<input
value={query ?? ''}
onChange={(e) => setQuery(e.currentTarget.value)}
placeholder="Search…"
/>
);
}const [pos, setPos] = useThrottleState({ x: 0, y: 0 }, 100);
useEffect(() => {
const onMove = (e: MouseEvent) => setPos({ x: e.clientX, y: e.clientY });
window.addEventListener('mousemove', onMove);
return () => window.removeEventListener('mousemove', onMove);
}, []);const [count, setCount] = useThrottleState(0, 250);
// The first click after idle applies +1 immediately,
// subsequent clicks within the window collapse into one final +1
<button onClick={() => setCount((x) => x + 1)}>+1 (throttled)</button>const [delay, setDelay] = useState(300);
const [text, setText] = useThrottleState('', delay);
// The new delay takes effect on the next setText call- Leading + trailing: first write is immediate; the last write within the window fires at the end of the window.
- Coalescing: calls within the window are merged; the latest value/updater wins.
- Functional updaters are supported; the last updater provided within the window is used.
- Stable setter:
setThrottleStateidentity does not change between renders. - Unmount-safe: pending updates are cleared on unmount.
- Changing
delayMs: does not affect an already scheduled update.
- High-frequency sources:
mousemove,scroll,resize, drag, input streams. - You want a quick first response and a single finalization with the "latest at the end" value.
- Limiting the frequency of expensive recalculations/requests without losing responsiveness.
- You want “only the last after a pause” — use
useDebounceState. - You need a strict periodic schedule — use a timer/loop.
- You need a mode without trailing or a different combination — use low-level
useThrottleCallback.
Exported types
-
UseThrottleStateSetAction<State>- Direct value:
State. - Or functional updater:
(prev: State) => State.
- Direct value:
-
UseThrottleStateDispatch<State>- Throttled state setter:
(action: UseThrottleStateSetAction<State>) => void.
- Throttled state setter:
-
UseThrottleStateReturn<State>- Tuple:
[state: State, setThrottleState: UseThrottleStateDispatch<State>].
- Tuple: