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-useis 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
reactandreact-domare peer dependencies. You must have them installed in your project already —react-usedoes 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
useCounterlogs aconsole.error(it does not throw) ifinitialValue,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 — useremoveAt(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)throwsError: State '<value>' is not a valid stateif 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. Passingcapacity < 1throwsError: 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
useMultiStateValidatorthrows ifstatesis 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
defaultStateargument. Without it,useMedialogs a hydration-mismatch warning because the server cannot readwindow.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
stylesoption (defaulttrue) makes the hook applyuser-select: noneto the track while sliding. Setstyles: falseto 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-easingfunction (e.g.inCirc,outQuad,inOutSine). An invalid name logs an error and returns0.
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
useLocalStoragethrowsError: useLocalStorage key may not be falsyif you pass an empty/falsy key. Always pass a non-empty string key. On the server (nowindow), 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()fromuseAsyncRetrywhile 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 (viafast-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.useEffectinstead.
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
Debounced search box
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.