# react-use User Guide

`react-use` is a large collection of essential React Hooks. It packages roughly
100 small, focused, well-tested hooks — for state, sensors, UI, animations,
side-effects, and component lifecycle — behind a single import. Instead of
re-implementing a debounce, a `localStorage` binding, a media query listener, or
an async-state machine in every project, you import the matching hook and wire it
into your component.

This guide shows you how to install the package and use every hook it exports,
grouped by category, with copy-paste-ready examples.

> [!NOTE]
> `react-use` is a **hook library**, not an application. There is no CLI, no
> server, and no configuration file. You consume it by importing hooks into your
> own React components. Everything in this guide is code you write inside a React
> app.

---

## 1. Quick Start

Install the package and start using a hook in under a minute.

```bash
npm install react-use
```

```tsx
import React from 'react';
import { useToggle, useCounter } from 'react-use';

function Demo() {
  const [on, toggle] = useToggle(false);
  const [count, { inc, dec, reset }] = useCounter(0);

  return (
    <div>
      <p>Switch is {on ? 'ON' : 'OFF'}</p>
      <button onClick={() => toggle()}>Toggle</button>

      <p>Count: {count}</p>
      <button onClick={() => inc()}>+</button>
      <button onClick={() => dec()}>-</button>
      <button onClick={() => reset()}>reset</button>
    </div>
  );
}
```

Every hook is exported by name from the package root, so you import only what you
use and a tree-shaking bundler drops the rest:

```tsx
import { useDebounce, useLocalStorage, useMouse } from 'react-use';
```

> [!TIP]
> The package ships both a CommonJS build (`lib/`) and an ES-module build
> (`esm/`) and declares `"sideEffects": false`, so modern bundlers (webpack,
> Vite, Rollup, esbuild) tree-shake unused hooks automatically. Import named
> hooks from `'react-use'` and ship only what you call.

---

## 2. Installation

### 2.1 Requirements

| Requirement | Detail |
|---|---|
| `react` | Any version (peer dependency, declared as `*`). Hooks require React **16.8+** for Hooks support. |
| `react-dom` | Any version (peer dependency, declared as `*`). |
| Bundler | Any bundler that resolves `package.json` `module`/`main` fields (Vite, webpack, Rollup, Parcel, esbuild). |
| TypeScript | Optional. The package ships its own type definitions (`lib/index.d.ts`); no `@types/react-use` needed. |

> [!IMPORTANT]
> `react` and `react-dom` are **peer dependencies**. You must have them installed
> in your project already — `react-use` does not bundle React. If you see a
> "could not find react" error, install React first.

### 2.2 Install with your package manager

=== "npm"

    ```bash
    npm install react-use
    ```

=== "yarn"

    ```bash
    yarn add react-use
    ```

=== "pnpm"

    ```bash
    pnpm add react-use
    ```

### 2.3 Verify the install

```tsx
import { useFirstMountState } from 'react-use';

function Probe() {
  const isFirstMount = useFirstMountState();
  return <span>{isFirstMount ? 'first render' : 're-render'}</span>;
}
```

If this compiles and renders without a module-resolution error, the package is
installed correctly.

> [!NOTE]
> The package is published under the **Unlicense** (public domain). You can use,
> copy, modify, and redistribute it without attribution or license terms.

---

## 3. How to Use This Guide

Every hook follows the same documentation shape:

- **What it does** — one sentence.
- **Signature** — the call shape and what it returns.
- **Example** — a runnable snippet.

The hooks are grouped into the same categories the library itself uses:

| Category | What it covers | Section |
|---|---|---|
| **State** | Local state containers: toggles, counters, lists, maps, sets, history | [§4](#4-state-hooks) |
| **Sensors** | Read the browser/device: mouse, scroll, media queries, battery, network | [§5](#5-sensor-hooks) |
| **UI** | Drive UI behaviors: clipboard, fullscreen, click-away, drag-drop, media | [§6](#6-ui-hooks) |
| **Animation & Timing** | Frames, intervals, timeouts, throttling, tweening | [§7](#7-animation--timing-hooks) |
| **Side-effects** | Persisted/external state: storage, cookies, async, title, favicon | [§8](#8-side-effect-hooks) |
| **Lifecycle** | Mount/unmount/update effects and render utilities | [§9](#9-lifecycle-hooks) |

A condensed alphabetical index of all exports is in [§12 Reference](#12-reference).

---

## 4. State Hooks

These hooks give you richer state containers than the bare `useState`.

### useToggle / useBoolean

Toggle a boolean, or set it explicitly.

```tsx
import { useToggle } from 'react-use';

const [value, toggle] = useToggle(true);
// toggle()       -> flips the value
// toggle(true)   -> sets to exactly true (a non-boolean arg flips)
```

`useBoolean` is an alias of `useToggle` — same behavior, friendlier name.

### useCounter / useNumber

A numeric counter with increment/decrement/set/reset and optional `min`/`max`
clamping.

```tsx
import { useCounter } from 'react-use';

const [count, { inc, dec, get, set, reset }] = useCounter(5, 10, 0);
// initialValue=5, max=10, min=0
inc();      // +1 (clamped to max)
dec(2);     // -2 (clamped to min)
set(7);     // set exact value
reset();    // back to initial
```

`useNumber` is an alias of `useCounter`.

> [!WARNING]
> `useCounter` logs a `console.error` (it does not throw) if `initialValue`,
> `min`, `max`, or a delta is not a number. Pass numbers only.

### useList

An array with a full set of mutation helpers.

```tsx
import { useList } from 'react-use';

const [list, { set, push, updateAt, insertAt, update, updateFirst, upsert,
  sort, filter, removeAt, clear, reset }] = useList([1, 2, 3]);

push(4);                 // [1,2,3,4]
updateAt(0, 9);          // [9,2,3,4]
removeAt(1);             // [9,3,4]
sort((a, b) => a - b);
clear();                 // []
reset();                 // back to [1,2,3]
```

> [!NOTE]
> `remove(index)` still works but is **deprecated** — use `removeAt(index)`.

### useMap

A key/value object with stable setter helpers.

```tsx
import { useMap } from 'react-use';

const [map, { set, setAll, remove, reset, get }] = useMap({ a: 1 });
set('b', 2);        // { a: 1, b: 2 }
remove('a');        // { b: 2 }
get('b');           // 2
```

### useSet

A `Set` with add/remove/toggle/has helpers.

```tsx
import { useSet } from 'react-use';

const [set, { add, has, remove, toggle, reset, clear }] = useSet(new Set(['a']));
add('b');
toggle('a');   // removes 'a'
has('b');      // true
```

### useQueue

A FIFO queue with `add`, `remove`, and `first`/`last`/`size` accessors.

```tsx
import { useQueue } from 'react-use';

const { add, remove, first, last, size } = useQueue<number>();
add(1); add(2);
remove();   // returns 1, queue is now [2]
```

### useStateList

Cycle through a fixed list of states with wrap-around navigation.

```tsx
import { useStateList } from 'react-use';

const { state, prev, next, setStateAt, setState, currentIndex, isFirst, isLast } =
  useStateList(['red', 'green', 'blue']);

next();              // -> 'green'
setStateAt(-1);      // -> 'blue' (negative index counts from the end)
setState('red');     // jump to a specific value
```

> [!WARNING]
> `setState(value)` throws `Error: State '<value>' is not a valid state` if the
> value is not in the list. Use a value that exists in the array.

### useStateWithHistory

`useState` that records a bounded undo/redo history.

```tsx
import { useStateWithHistory } from 'react-use';

const [value, setValue, history] = useStateWithHistory('a', 10);
// history.history  -> array of past values
// history.position -> current index
setValue('b');
history.back();      // step back one
history.forward();   // step forward one
history.go(0);       // jump to absolute position
```

> [!CAUTION]
> The `capacity` (second argument) must be greater than 1. Passing `capacity < 1`
> throws `Error: Capacity has to be greater than 1`.

### useGetSet

State where reads always return the latest value via a getter — avoids stale
closures in async callbacks.

```tsx
import { useGetSet } from 'react-use';

const [get, set] = useGetSet(0);
set(10);
setTimeout(() => console.log(get()), 1000); // always the freshest value
```

### useGetSetState

Combines `useGetSet` with patch-style object updates.

```tsx
import { useGetSetState } from 'react-use';

const [get, setState] = useGetSetState({ count: 0, name: 'init' });
setState({ count: 1 });   // merges patch into current state
get();                    // { count: 1, name: 'init' }
```

### useSetState

`useState` for objects that merges patches instead of replacing (like the old
class `setState`).

```tsx
import { useSetState } from 'react-use';

const [state, setState] = useSetState({ a: 1, b: 2 });
setState({ a: 9 });                 // { a: 9, b: 2 }
setState((prev) => ({ b: prev.b + 1 }));
```

### useDefault

Falls back to a default whenever the value is set to `null` or `undefined`.

```tsx
import { useDefault } from 'react-use';

const [value, setValue] = useDefault('guest', 'alice');
setValue(null);   // value is now 'guest'
```

### useMethods

A lighter alternative to `useReducer`: define named methods that return the next
state.

```tsx
import { useMethods } from 'react-use';

const initialState = { count: 0 };
const createMethods = (state) => ({
  reset: () => initialState,
  increment: () => ({ count: state.count + 1 }),
  decrement: () => ({ count: state.count - 1 }),
});

const [state, methods] = useMethods(createMethods, initialState);
methods.increment();
```

### useMediatedState

`useState` with a mediator that transforms every incoming value before it is
stored.

```tsx
import { useMediatedState } from 'react-use';

// Keep only digits
const [value, setValue] = useMediatedState(
  (s: string) => s.replace(/[^d]/g, ''),
  ''
);
```

### useStateValidator / useMultiStateValidator

Run a validator function against a state value (or several states) and expose its
validity.

```tsx
import { useStateValidator } from 'react-use';

const [num, setNum] = React.useState(0);
const [[isValid]] = useStateValidator(num, (s) => [s > 0 && s < 10]);
```

`useMultiStateValidator` validates an array/object of states together.

> [!NOTE]
> `useMultiStateValidator` throws if `states` is not an object or array. Always
> pass an array or object of states.

### usePrevious / usePreviousDistinct

Return a value from the previous render. `usePreviousDistinct` only updates when
the value actually changes (with an optional comparator).

```tsx
import { usePrevious, usePreviousDistinct } from 'react-use';

const prev = usePrevious(count);
const prevDistinct = usePreviousDistinct(count, (a, b) => a === b);
```

### useLatest

A ref that always holds the latest value — handy inside event handlers and
timeouts that would otherwise capture a stale value.

```tsx
import { useLatest } from 'react-use';

const latest = useLatest(value);
// latest.current is always current, even in old closures
```

### useObservable

Subscribe to an RxJS-style observable and re-render on each emission.

```tsx
import { useObservable } from 'react-use';

const value = useObservable(observable$, initialValue);
```

### useRafState

`useState` whose setter is deferred to the next animation frame — batches rapid
updates for smoother rendering.

```tsx
import { useRafState } from 'react-use';

const [state, setState] = useRafState({ x: 0, y: 0 });
```

### useFirstMountState / useRendersCount

`useFirstMountState` returns `true` only on the first render;
`useRendersCount` returns how many times the component has rendered.

```tsx
import { useFirstMountState, useRendersCount } from 'react-use';

const isFirst = useFirstMountState();
const renders = useRendersCount();
```

### State factories: createGlobalState, createReducer, createReducerContext, createStateContext, createBreakpoint, createMemo

These are **factory functions** — call them once at module scope to produce a
reusable hook or provider.

**createGlobalState** — share one state value across components without a
provider:

```tsx
import { createGlobalState } from 'react-use';

const useGlobalCount = createGlobalState(0);

function A() {
  const [count, setCount] = useGlobalCount();
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
function B() {
  const [count] = useGlobalCount();   // sees the same value as A
  return <span>{count}</span>;
}
```

**createStateContext** — a `useState`-backed context with a typed provider:

```tsx
import { createStateContext } from 'react-use';

const [useSharedText, SharedTextProvider] = createStateContext('');
// Wrap your tree in <SharedTextProvider>, then call useSharedText() anywhere.
```

**createReducerContext** — same idea, backed by `useReducer`.

**createReducer** — build a `useReducer`-style hook with Redux-style middleware
(e.g. a logger or thunk):

```tsx
import { createReducer } from 'react-use';
import logger from 'redux-logger';
import thunk from 'redux-thunk';

const useThunkReducer = createReducer(thunk, logger);
const [state, dispatch] = useThunkReducer(reducer, initialState);
```

**createBreakpoint** — make a hook that returns the current named breakpoint:

```tsx
import { createBreakpoint } from 'react-use';

const useBreakpoint = createBreakpoint({ L: 1440, M: 1024, S: 768 });
const breakpoint = useBreakpoint();  // 'S' | 'M' | 'L'
```

**createMemo** — turn any pure function into a memoizing hook:

```tsx
import { createMemo } from 'react-use';

const useFib = createMemo(fibonacci);
const result = useFib(10);  // memoized by argument
```

---

## 5. Sensor Hooks

These hooks read browser and device state and re-render when it changes.

### useMouse / useMouseHovered

Track mouse position relative to a referenced element.

```tsx
import { useMouse } from 'react-use';

const ref = React.useRef(null);
const { docX, docY, posX, posY, elX, elY, elW, elH } = useMouse(ref);
// docX/docY: position in document; elX/elY: position inside the element
```

`useMouseHovered` adds options: `whenHovered` (only track while hovering) and
`bound` (clamp coordinates to the element box).

### useScroll / useScrolling / useWindowScroll

```tsx
import { useScroll, useScrolling, useWindowScroll } from 'react-use';

const ref = React.useRef(null);
const { x, y } = useScroll(ref);          // element scroll position
const scrolling = useScrolling(ref);      // true while actively scrolling
const win = useWindowScroll();            // { x, y } of the window
```

### useWindowSize / useMeasure / useSize

```tsx
import { useWindowSize, useMeasure } from 'react-use';

const { width, height } = useWindowSize();

const [ref, { width: w, height: h }] = useMeasure();
return <div ref={ref}>I am {w}px wide</div>;
```

`useMeasure` uses `ResizeObserver` to report an element's content rectangle.
`useSize` wraps a render-prop element with a hidden resize-detecting iframe and
returns `[sizedElement, { width, height }]`.

### useMedia

Track a CSS media query.

```tsx
import { useMedia } from 'react-use';

const isWide = useMedia('(min-width: 768px)');
const isWideSSR = useMedia('(min-width: 768px)', true); // default for SSR
```

> [!WARNING]
> When server-side rendering, pass the second `defaultState` argument. Without
> it, `useMedia` logs a hydration-mismatch warning because the server cannot read
> `window.matchMedia`.

### useHover / useHoverDirty

```tsx
import { useHover } from 'react-use';

const element = (hovered) => <div>{hovered ? 'Hovered!' : 'Hover me'}</div>;
const [node, isHovered] = useHover(element);
return node;
```

`useHoverDirty` takes a ref instead of a render element:
`const isHovered = useHoverDirty(ref);`

### useIntersection

Wrap the `IntersectionObserver` API.

```tsx
import { useIntersection } from 'react-use';

const ref = React.useRef(null);
const entry = useIntersection(ref, { threshold: 0.5 });
const visible = entry?.isIntersecting;
```

### useKey / useKeyPress / useKeyPressEvent

```tsx
import { useKey, useKeyPress } from 'react-use';

useKey('ArrowUp', () => console.log('up!'));
useKey((e) => e.key === 'Enter', submit);

const [pressed] = useKeyPress('a');   // true while 'a' is held
```

`useKeyPressEvent(key, onDown, onUp)` fires callbacks on key transitions.

### useLongPress

Bind long-press handlers to an element.

```tsx
import { useLongPress } from 'react-use';

const bind = useLongPress(() => console.log('held!'), { delay: 500 });
return <button {...bind}>Press and hold</button>;
```

### useStartTyping

Fire a callback when the user begins typing while no input is focused.

```tsx
import { useStartTyping } from 'react-use';

useStartTyping((e) => inputRef.current?.focus());
```

### useBattery

Read the device battery (where the Battery Status API exists).

```tsx
import { useBattery } from 'react-use';

const battery = useBattery();
if (battery.isSupported && battery.fetched) {
  // battery.level, battery.charging, battery.chargingTime, battery.dischargingTime
}
```

### useGeolocation

```tsx
import { useGeolocation } from 'react-use';

const { loading, latitude, longitude, accuracy, error } = useGeolocation();
```

### useNetworkState

```tsx
import { useNetworkState } from 'react-use';

const { online, effectiveType, downlink, rtt, since } = useNetworkState();
```

### useOrientation / useMotion

`useOrientation` reports screen `{ angle, type }`; `useMotion` reports
accelerometer/gyroscope readings from the `devicemotion` event.

### useMediaDevices

List available media input/output devices.

```tsx
import { useMediaDevices } from 'react-use';

const state = useMediaDevices();   // { devices: [{ deviceId, kind, label, groupId }] }
```

### usePermission

Query the Permissions API.

```tsx
import { usePermission } from 'react-use';

const state = usePermission({ name: 'microphone' }); // 'granted' | 'denied' | 'prompt' | ''
```

### useIdle

Detect user inactivity.

```tsx
import { useIdle } from 'react-use';

const isIdle = useIdle(60e3);   // true after 60s of no activity
```

### useLocation / useSearchParam / useHash

Read browser location state. `useLocation` patches `history.pushState`/
`replaceState` so it updates on programmatic navigation.

```tsx
import { useLocation, useSearchParam, useHash } from 'react-use';

const location = useLocation();          // { pathname, search, hash, ... }
const tab = useSearchParam('tab');       // value of ?tab=
const [hash, setHash] = useHash();       // read/write window.location.hash
```

### usePageLeave / useScrollbarWidth / usePinchZoom / useScratch

- `usePageLeave(cb)` — fire when the mouse leaves the page.
- `useScrollbarWidth()` — the browser's scrollbar width in px.
- `usePinchZoom(ref)` — detect two-pointer pinch gestures (`{ zoomingState, pinchState }`).
- `useScratch(params)` — track click-drag "scratch" gestures over an element.

---

## 6. UI Hooks

### useClickAway

Run a callback when a click lands outside a referenced element.

```tsx
import { useClickAway } from 'react-use';

const ref = React.useRef(null);
useClickAway(ref, () => closeMenu());
return <div ref={ref}>menu</div>;
```

### useCopyToClipboard

```tsx
import { useCopyToClipboard } from 'react-use';

const [state, copyToClipboard] = useCopyToClipboard();
copyToClipboard('hello');
// state.value, state.error, state.noUserInteraction
```

> [!WARNING]
> Only strings and numbers can be copied. Copying any other type, or an empty
> string, sets `state.error` (and logs to the console in development).

### useFullscreen

Put a referenced element into fullscreen while `enabled` is true.

```tsx
import { useFullscreen } from 'react-use';

const ref = React.useRef(null);
const [show, setShow] = React.useState(false);
const isFullscreen = useFullscreen(ref, show, { onClose: () => setShow(false) });
```

### useDrop / useDropArea

`useDrop` listens for drops/pastes on the whole document; `useDropArea` returns
bindable handlers for a single element.

```tsx
import { useDropArea } from 'react-use';

const [bond, state] = useDropArea({
  onFiles: (files) => console.log(files),
  onText: (text) => console.log(text),
  onUri: (uri) => console.log(uri),
});
return <div {...bond}>{state.over ? 'Drop here' : 'Drag files in'}</div>;
```

### useSlider

Make an element draggable as a slider track.

```tsx
import { useSlider } from 'react-use';

const ref = React.useRef(null);
const { isSliding, value } = useSlider(ref, {
  onScrub: (v) => console.log(v),     // v is 0..1
  vertical: false,
  reverse: false,
});
```

> [!NOTE]
> The `styles` option (default `true`) makes the hook apply
> `user-select: none` to the track while sliding. Set `styles: false` to manage
> styling yourself.

### useAudio / useVideo

Render a media element and control it imperatively.

```tsx
import { useAudio } from 'react-use';

const [audio, state, controls, ref] = useAudio({
  src: '/song.mp3',
  autoPlay: false,
});

return (
  <div>
    {audio}
    <p>{state.playing ? 'Playing' : 'Paused'} — {state.time.toFixed(1)}s</p>
    <button onClick={controls.play}>Play</button>
    <button onClick={controls.pause}>Pause</button>
    <button onClick={() => controls.seek(state.time + 10)}>+10s</button>
    <button onClick={controls.mute}>Mute</button>
    <input type="range" min={0} max={1} step={0.1}
      onChange={(e) => controls.volume(Number(e.target.value))} />
  </div>
);
```

`useVideo` has the identical API but renders a `<video>` element.

> [!IMPORTANT]
> You must render the returned element (`{audio}` / `{video}`) for the hook to
> work — it owns the underlying DOM node. In development, the hook logs an error
> if the element is never mounted.

### useSpeech

Speak text with the Speech Synthesis API.

```tsx
import { useSpeech } from 'react-use';

const state = useSpeech('Hello world', { rate: 1, pitch: 1, volume: 1 });
// state.isPlaying, state.status, state.voiceInfo
```

### useVibrate

Vibrate the device (where supported).

```tsx
import { useVibrate } from 'react-use';

useVibrate(isEnabled, [300, 100, 300], false); // pattern, loop=false
```

### useCss

Generate a scoped CSS class at runtime (powered by `nano-css`).

```tsx
import { useCss } from 'react-use';

const className = useCss({ color: 'red', '&:hover': { color: 'blue' } });
return <div className={className}>Styled</div>;
```

### useLockBodyScroll

Lock scrolling on the nearest scrollable body while mounted/enabled.

```tsx
import { useLockBodyScroll } from 'react-use';

useLockBodyScroll(isModalOpen);
```

---

## 7. Animation & Timing Hooks

### useRaf / useRafLoop

`useRaf(ms, delay)` returns a `0 → 1` progress value over `ms` using
`requestAnimationFrame`. `useRafLoop(cb)` runs a callback every frame with
start/stop controls.

```tsx
import { useRaf, useRafLoop } from 'react-use';

const progress = useRaf(2000);   // animates 0..1 over 2s

const [stop, start, isActive] = useRafLoop((time) => {
  // runs each frame
});
```

### useInterval / useHarmonicIntervalFn

`useInterval(cb, delay)` runs a callback on an interval; pass `null` as the delay
to pause it. `useHarmonicIntervalFn` synchronizes multiple intervals to fire on
the same tick.

```tsx
import { useInterval } from 'react-use';

const [delay, setDelay] = React.useState(1000);
useInterval(() => tick(), delay);   // pass null to pause
```

### useTimeout / useTimeoutFn

`useTimeoutFn(fn, ms)` returns `[isReady, cancel, reset]`. `useTimeout(ms)` is the
same but re-renders the component when the timeout fires.

```tsx
import { useTimeoutFn } from 'react-use';

const [isReady, cancel, reset] = useTimeoutFn(() => doThing(), 5000);
// isReady() -> false (pending) | true (fired) | null (cancelled)
```

### useTween

Animate a `0 → 1` value through an easing function.

```tsx
import { useTween } from 'react-use';

const t = useTween('inCirc', 1000);   // eased progress 0..1
```

> [!NOTE]
> The easing name must be a valid `ts-easing` function (e.g. `inCirc`,
> `outQuad`, `inOutSine`). An invalid name logs an error and returns `0`.

### useThrottle / useThrottleFn

Throttle a value or a function so it updates at most once per interval.

```tsx
import { useThrottle } from 'react-use';

const throttled = useThrottle(fastChangingValue, 500);
```

---

## 8. Side-effect Hooks

### useLocalStorage / useSessionStorage

Bind a state value to `localStorage`/`sessionStorage`, with JSON serialization by
default.

```tsx
import { useLocalStorage } from 'react-use';

const [name, setName, remove] = useLocalStorage('name', 'Anonymous');
setName('Alice');   // persisted across reloads
remove();           // clear the key
```

Custom serialization:

```tsx
const [value, setValue] = useLocalStorage('key', 0, { raw: false,
  serializer: (v) => String(v),
  deserializer: (v) => Number(v),
});
```

> [!CAUTION]
> `useLocalStorage` throws `Error: useLocalStorage key may not be falsy` if you
> pass an empty/falsy key. Always pass a non-empty string key. On the server (no
> `window`), the hook returns the initial value and no-op setters.

`useSessionStorage(key, initialValue, raw?)` is the session-scoped equivalent.

### useCookie

Read and write a single cookie (via `js-cookie`).

```tsx
import { useCookie } from 'react-use';

const [value, updateCookie, deleteCookie] = useCookie('token');
updateCookie('abc123', { expires: 7 });
deleteCookie();
```

### useAsync / useAsyncFn / useAsyncRetry

Drive an async function and expose `{ loading, value, error }`.

```tsx
import { useAsync } from 'react-use';

const state = useAsync(async () => {
  const res = await fetch('/api/user');
  return res.json();
}, []);

if (state.loading) return <Spinner />;
if (state.error) return <Error message={state.error.message} />;
return <Profile data={state.value} />;
```

`useAsyncFn` returns `[state, callback]` so you trigger the call manually (e.g. on
submit). `useAsyncRetry` adds a `retry()` method to re-run the function.

```tsx
import { useAsyncFn } from 'react-use';

const [state, submit] = useAsyncFn(async (form) => postForm(form), []);
return <button disabled={state.loading} onClick={() => submit(form)}>Save</button>;
```

> [!NOTE]
> Calling `retry()` from `useAsyncRetry` while a request is still loading is a
> no-op (and logs a notice in development).

### useTitle / useFavicon

Set the document title or favicon for as long as the component is mounted.

```tsx
import { useTitle, useFavicon } from 'react-use';

useTitle('Dashboard');                       // restores on unmount if option set
useFavicon('https://example.com/icon.png');
```

`useTitle(title, { restoreOnUnmount: true })` restores the previous title when the
component unmounts.

### useDebounce

Run a function after a value stops changing for `ms`.

```tsx
import { useDebounce } from 'react-use';

const [query, setQuery] = React.useState('');
const [isReady, cancel] = useDebounce(() => search(query), 500, [query]);
```

### useBeforeUnload

Warn the user before they leave the page.

```tsx
import { useBeforeUnload } from 'react-use';

useBeforeUnload(hasUnsavedChanges, 'You have unsaved changes!');
```

### useError

Get a function that throws an error into the nearest React error boundary.

```tsx
import { useError } from 'react-use';

const dispatchError = useError();
// later: dispatchError(new Error('something failed'));
```

### usePermission

(See [§5 Sensors](#usepermission) — `usePermission` reads the Permissions API and
is also useful as a side-effect gate before requesting camera/mic access.)

---

## 9. Lifecycle Hooks

### useMount / useUnmount / useLifecycles

```tsx
import { useMount, useUnmount, useLifecycles } from 'react-use';

useMount(() => console.log('mounted'));
useUnmount(() => console.log('unmounting'));
useLifecycles(
  () => console.log('mount'),
  () => console.log('unmount')
);
```

### useEffectOnce

Run an effect exactly once on mount (an empty-deps `useEffect` with a clearer
name).

```tsx
import { useEffectOnce } from 'react-use';

useEffectOnce(() => {
  const sub = source.subscribe();
  return () => sub.unsubscribe();
});
```

### useUpdateEffect

Like `useEffect`, but skips the first render — runs only on updates.

```tsx
import { useUpdateEffect } from 'react-use';

useUpdateEffect(() => {
  console.log('value changed (not on mount)');
}, [value]);
```

### useMountedState / usePromise / useUnmountPromise

Guard async work against updates after unmount.

```tsx
import { useMountedState } from 'react-use';

const isMounted = useMountedState();
fetchData().then((data) => {
  if (isMounted()) setState(data);  // avoid setting state after unmount
});
```

`usePromise` and `useUnmountPromise` wrap a promise so it never resolves/rejects
after the component unmounts.

### useIsomorphicLayoutEffect

`useLayoutEffect` in the browser, `useEffect` on the server — avoids the SSR
warning React emits for `useLayoutEffect`.

```tsx
import { useIsomorphicLayoutEffect } from 'react-use';

useIsomorphicLayoutEffect(() => { /* measure DOM */ }, []);
```

### useDeepCompareEffect / useShallowCompareEffect / useCustomCompareEffect

`useEffect` variants that compare dependencies by value rather than reference.

```tsx
import { useDeepCompareEffect } from 'react-use';

useDeepCompareEffect(() => {
  // runs only when `options` deeply changes
}, [options]);
```

- `useDeepCompareEffect` — deep equality (via `fast-deep-equal`).
- `useShallowCompareEffect` — shallow equality.
- `useCustomCompareEffect(effect, deps, depsEqual)` — your own comparator.

> [!WARNING]
> In development these hooks warn if you pass no dependencies, or dependencies
> that are all primitive values — in those cases use plain `React.useEffect`
> instead.

### useEvent

Subscribe to an event on a target for the lifetime of the component.

```tsx
import { useEvent } from 'react-use';

useEvent('keydown', (e) => console.log(e.key));         // defaults to window
useEvent('scroll', onScroll, scrollContainerEl);
```

### useUpdate

Return a function that forces a re-render.

```tsx
import { useUpdate } from 'react-use';

const update = useUpdate();
// call update() to force a re-render
```

### useLogger

Log a component's mount/update/unmount lifecycle to the console (debugging aid).

```tsx
import { useLogger } from 'react-use';

useLogger('MyComponent', props);
```

### useEnsuredForwardedRef / ensuredForwardRef

Guarantee a usable ref inside a `forwardRef` component even when the parent does
not pass one.

```tsx
import { ensuredForwardRef } from 'react-use';

const Input = ensuredForwardRef((props, ref) => {
  // ref is always a valid MutableRefObject here
  return <input ref={ref} {...props} />;
});
```

---

## 10. Common Recipes

### Debounced search box

```tsx
import { useState } from 'react';
import { useDebounce } from 'react-use';

function Search() {
  const [text, setText] = useState('');
  const [results, setResults] = useState([]);

  useDebounce(async () => {
    if (!text) return;
    const r = await fetch(`/api/search?q=${text}`).then((res) => res.json());
    setResults(r);
  }, 400, [text]);

  return (
    <>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <ul>{results.map((r) => <li key={r.id}>{r.name}</li>)}</ul>
    </>
  );
}
```

### Persisted dark-mode toggle

```tsx
import { useLocalStorage, useMedia } from 'react-use';

function useDarkMode() {
  const prefersDark = useMedia('(prefers-color-scheme: dark)', false);
  const [dark, setDark] = useLocalStorage('dark-mode', prefersDark);
  return [dark, () => setDark(!dark)] as const;
}
```

### Close a dropdown on outside click or Escape

```tsx
import { useRef } from 'react';
import { useClickAway, useKey } from 'react-use';

function Dropdown({ onClose, children }) {
  const ref = useRef(null);
  useClickAway(ref, onClose);
  useKey('Escape', onClose);
  return <div ref={ref}>{children}</div>;
}
```

---

## 11. Troubleshooting

### Error: `useLocalStorage key may not be falsy`

**Cause:** You called `useLocalStorage('', ...)` or passed an empty/undefined key.

**Solution:** Pass a non-empty string key: `useLocalStorage('my-key', initial)`.

**Prevention:** Never compute the key from a value that can be empty before the
hook runs.

### Error: `Capacity has to be greater than 1`

**Cause:** `useStateWithHistory(initial, capacity)` was called with `capacity < 1`.

**Solution:** Pass a capacity of at least 2 (the default is `10`).

### Error: `State '<x>' is not a valid state (does not exist in state list)`

**Cause:** `useStateList(...).setState(value)` was called with a value not present
in the list.

**Solution:** Only call `setState` with a value that exists in the array, or use
`setStateAt(index)` / `next()` / `prev()`.

### Error: `useReducerContext must be used inside a ReducerProvider`

**Cause:** A hook from `createReducerContext` was called in a component that is not
wrapped by its generated provider. (`createStateContext` produces the analogous
`useStateContext must be used inside a StateProvider`.)

**Solution:** Wrap the consuming subtree in the `Provider` the factory returned.

### Warning: `useMedia` hydration mismatch on the server

**Cause:** `useMedia(query)` was called during SSR without a `defaultState`.

**Solution:** Pass an explicit default: `useMedia('(min-width: 768px)', false)`.

**Prevention:** Always supply the second argument when rendering on the server.

### Warning: `useDeepCompareEffect should not be used with dependencies that are all primitive values`

**Cause:** You passed only primitives (numbers, strings, booleans) to a
compare-effect hook.

**Solution:** Use plain `React.useEffect` for primitive dependencies; reserve the
compare-effect hooks for objects/arrays.

### `useAudio` / `useVideo` does nothing and logs "ref to element is empty"

**Cause:** You did not render the element the hook returns as its first value.

**Solution:** Render it: `const [audio, state, controls] = useAudio(...); return <>{audio}</>;`

### A sensor hook returns an empty/"unsupported" value

**Cause:** Hooks like `useBattery`, `useMediaDevices`, `useVibrate`, and
`usePermission` depend on browser APIs that may be absent. The library swaps in a
no-op/mock implementation when the API is missing.

**Solution:** Check the support flag the hook provides (e.g.
`battery.isSupported`) and provide a fallback UI. There is no error to fix — the
API simply is not available in that environment.

### `import "nano-css/addon/vcssom"` fails to resolve (Vite)

**Cause:** A known dependency-optimization issue with Vite and `useCss`'s
`nano-css` sub-path imports (community issue #2684).

**Solution:** If you do not use `useCss`, import only the hooks you need so the
bundler never pulls in `nano-css`. If you do, add `nano-css` to your bundler's
optimize/include list.

---

## 12. Reference

### Import pattern

```tsx
import { useToggle, useCounter, useLocalStorage /* ... */ } from 'react-use';
```

### Hooks NOT exported from the package root

Two hooks live in the source but are intentionally **not** re-exported from
`'react-use'` because they require peer dependencies you may not have installed:

| Hook | Reason | How to use |
|---|---|---|
| `useKeyboardJs` | Requires the `keyboardjs` package | Import directly: `import useKeyboardJs from 'react-use/lib/useKeyboardJs'` and install `keyboardjs`. |
| `useSpring` | Requires the `rebound` package | Import directly from its source path and install `rebound`. |

### Deprecated APIs

| API | Status | Use instead |
|---|---|---|
| `useUpsert` | Deprecated | `useList(...)`'s `upsert` action |
| `useList(...).remove(index)` | Deprecated | `removeAt(index)` |

### Hook index by category

| Category | Hooks |
|---|---|
| **State** | `useToggle`, `useBoolean`, `useCounter`, `useNumber`, `useList`, `useUpsert`, `useMap`, `useSet`, `useQueue`, `useStateList`, `useStateWithHistory`, `useGetSet`, `useGetSetState`, `useSetState`, `useDefault`, `useMethods`, `useMediatedState`, `useStateValidator`, `useMultiStateValidator`, `usePrevious`, `usePreviousDistinct`, `useLatest`, `useObservable`, `useRafState`, `useFirstMountState`, `useRendersCount` |
| **State factories** | `createGlobalState`, `createReducer`, `createReducerContext`, `createStateContext`, `createBreakpoint`, `createMemo` |
| **Sensors** | `useMouse`, `useMouseHovered`, `useMouseWheel`, `useScroll`, `useScrolling`, `useWindowScroll`, `useWindowSize`, `useMeasure`, `useSize`, `useMedia`, `useHover`, `useHoverDirty`, `useIntersection`, `useKey`, `useKeyPress`, `useKeyPressEvent`, `useLongPress`, `useStartTyping`, `useBattery`, `useGeolocation`, `useNetworkState`, `useOrientation`, `useMotion`, `useMediaDevices`, `usePermission`, `useIdle`, `useLocation`, `useSearchParam`, `useHash`, `usePageLeave`, `useScrollbarWidth`, `usePinchZoom`, `useScratch` |
| **UI** | `useClickAway`, `useCopyToClipboard`, `useFullscreen`, `useDrop`, `useDropArea`, `useSlider`, `useAudio`, `useVideo`, `useSpeech`, `useVibrate`, `useCss`, `useLockBodyScroll` |
| **Animation & Timing** | `useRaf`, `useRafLoop`, `useInterval`, `useHarmonicIntervalFn`, `useTimeout`, `useTimeoutFn`, `useTween`, `useThrottle`, `useThrottleFn` |
| **Side-effects** | `useLocalStorage`, `useSessionStorage`, `useCookie`, `useAsync`, `useAsyncFn`, `useAsyncRetry`, `useTitle`, `useFavicon`, `useDebounce`, `useBeforeUnload`, `useError` |
| **Lifecycle** | `useMount`, `useUnmount`, `useLifecycles`, `useEffectOnce`, `useUpdateEffect`, `useMountedState`, `usePromise`, `useUnmountPromise`, `useIsomorphicLayoutEffect`, `useDeepCompareEffect`, `useShallowCompareEffect`, `useCustomCompareEffect`, `useEvent`, `useUpdate`, `useLogger`, `useEnsuredForwardedRef` (+ `ensuredForwardRef`) |

> [!NOTE]
> For architecture, the SSR strategy, build/format details, security notes, and
> contribution guidance, see the **Admin Guide**.

---

_Generated June 2026 from streamich/react-use at 9ef9535. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
