Jesse A. Green / notebook

react-use User 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.

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.

npm install react-use
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:

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

npm install react-use

yarn

yarn add react-use

pnpm

pnpm add react-use

2.3 Verify the install

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
Sensors Read the browser/device: mouse, scroll, media queries, battery, network §5
UI Drive UI behaviors: clipboard, fullscreen, click-away, drag-drop, media §6
Animation & Timing Frames, intervals, timeouts, throttling, tweening §7
Side-effects Persisted/external state: storage, cookies, async, title, favicon §8
Lifecycle Mount/unmount/update effects and render utilities §9

A condensed alphabetical index of all exports is in §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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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).

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.

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.

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.

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.

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).

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.

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.

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.

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.

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:

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:

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):

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:

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:

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.

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

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

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.

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

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.

import { useIntersection } from 'react-use';

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

useKey / useKeyPress / useKeyPressEvent

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.

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.

import { useStartTyping } from 'react-use';

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

useBattery

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

import { useBattery } from 'react-use';

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

useGeolocation

import { useGeolocation } from 'react-use';

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

useNetworkState

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.

import { useMediaDevices } from 'react-use';

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

usePermission

Query the Permissions API.

import { usePermission } from 'react-use';

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

useIdle

Detect user inactivity.

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.

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.

import { useClickAway } from 'react-use';

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

useCopyToClipboard

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.

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.

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.

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.

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.

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).

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).

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.

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.

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.

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.

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.

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.

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.

import { useLocalStorage } from 'react-use';

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

Custom serialization:

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).

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 }.

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.

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.

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.

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.

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.

import { useError } from 'react-use';

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

usePermission

(See §5 Sensors — 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

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).

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.

import { useUpdateEffect } from 'react-use';

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

useMountedState / usePromise / useUnmountPromise

Guard async work against updates after unmount.

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.

import { useIsomorphicLayoutEffect } from 'react-use';

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

useDeepCompareEffect / useShallowCompareEffect / useCustomCompareEffect

useEffect variants that compare dependencies by value rather than reference.

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.

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.

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).

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.

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

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

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

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

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.