react-use is a comprehensive collection of essential React hooks for handling side effects, state, and sensors. react-use-form-state is a specialized, lightweight helper specifically designed to simplify form state management without the overhead of larger libraries. react-use-gesture (now part of the @use-gesture family) provides robust utilities for handling touch, mouse, and pointer gestures with spring physics support. react-hooks is a legacy package that is no longer maintained and should be avoided in favor of modern, actively developed alternatives like react-use or framework-native solutions.
When building modern React applications, hooks have become the standard for managing state and side effects. However, the ecosystem is fragmented between massive utility collections, specialized tools, and abandoned legacy packages. Let's analyze react-use, react-use-form-state, react-use-gesture, and the deprecated react-hooks to understand their architectural roles and practical trade-offs.
react-use acts as a "batteries-included" toolkit. It exports over 100 hooks covering everything from browser sensors (like useBattery or useGeolocation) to advanced state management (useAsync, useLocalStorage). It aims to replace the need for writing custom hooks for common patterns.
// react-use: Comprehensive utility
import { useLocalStorage, useAsync } from 'react-use';
function UserProfile() {
// Syncs state with browser storage automatically
const [theme, setTheme] = useLocalStorage('theme', 'light');
// Handles loading, error, and value states for async calls
const { value: user, loading } = useAsync(async () => {
return fetch('/api/user').then(r => r.json());
});
if (loading) return <div>Loading...</div>;
return <div style={{ background: theme }}>{user.name}</div>;
}
react-use-form-state has a narrow, focused scope: managing controlled form inputs. It does not handle validation logic or submission strategies; it simply reduces the boilerplate of tracking value, onChange, and error states for multiple fields.
// react-use-form-state: Focused form helper
import useFormState from 'react-use-form-state';
function LoginForm() {
const [formState, { text, password }] = useFormState({
email: '',
password: ''
});
return (
<form>
{/* Spreads value and onChange automatically */}
<input {...text('email')} placeholder="Email" />
<input {...password('password')} placeholder="Password" />
<button type="submit">Login</button>
</form>
);
}
react-use-gesture (now evolved into the @use-gesture organization) specializes in pointer interactions. It abstracts the complexity of normalizing mouse, touch, and pointer events into a single stream of coordinates and velocity data, often used with animation libraries.
// react-use-gesture: Interaction handler
import { useDrag } from 'react-use-gesture';
function DraggableBox() {
const [{ x, y }, set] = useState({ x: 0, y: 0 });
// Binds drag events to update coordinates
const bind = useDrag(({ movement: [mx, my] }) => {
set({ x: mx, y: my });
});
return <div {...bind()} style={{ transform: `translate(${x}px, ${y}px)` }} />;
}
react-hooks was an early attempt at a utility collection but lacks the depth and maintenance of react-use. Its API surface is limited, and it has not kept pace with modern React patterns.
// react-hooks: Legacy pattern (Avoid)
import { useToggle } from 'react-hooks';
// While this simple toggle works, the library lacks updates
// for concurrent mode or modern server components.
const [isOn, toggle] = useToggle(false);
The most critical architectural decision here is avoiding technical debt.
react-hooks is officially deprecated. The repository is archived, and it receives no security patches or compatibility updates for React 18+ features. Using it introduces unnecessary risk.
// β DO NOT USE: Deprecated package
// import { useMedia } from 'react-hooks';
// Risk: May break with future React releases or lack SSR support.
react-use, react-use-form-state, and react-use-gesture are actively maintained (with react-use-gesture having migrated to the @use-gesture scope for better modularity). They support modern React features like concurrent rendering and strict mode.
// β
SAFE: Active maintenance
import { useMedia } from 'react-use'; // Actively updated
import { useDrag } from '@use-gesture/react'; // Modern successor
Each library approaches state differently based on its goal.
react-use often wraps complex logic inside the hook, returning multiple state variables and setters. This is powerful but can lead to large component signatures if you import many hooks.
// react-use: Returns multiple stateful values
const [state, setState, reset] = useSetState({ id: 1, name: 'Test' });
// You manage the shape of the state object directly inside the hook.
react-use-form-state enforces a specific structure for form data. It returns a proxy object that generates props for inputs, keeping the component JSX clean but limiting flexibility if your form needs non-standard behavior.
// react-use-form-state: Opinionated prop spreading
const [formState, { email }] = useFormState({ email: '' });
// <input {...email()} /> automatically wires value and onChange.
// Harder to customize if you need a complex onBlur handler.
react-use-gesture separates the gesture logic from the animation logic. It provides the data (coordinates, velocity), leaving the rendering to you (often via framer-motion or react-spring).
// react-use-gesture: Data provider for animations
const bind = useDrag(({ down, movement: [x] }) => ({
x: down ? x : 0,
immediate: down
}));
// You decide how to apply 'x' to the DOM or animation library.
You need to show battery status, network connectivity, and window dimensions.
react-useuseBattery, useNetwork, useWindowSize) that handle event listeners and cleanup internally.import { useBattery, useNetwork } from 'react-use';
function DashboardStatus() {
const battery = useBattery();
const network = useNetwork();
return (
<div>
<span>Battery: {battery.level * 100}%</span>
<span>Online: {network.online ? 'Yes' : 'No'}</span>
</div>
);
}
You need a quick contact form with name and message fields, no complex validation.
react-use-form-stateuseState for every single field in half.import useFormState from 'react-use-form-state';
function ContactForm() {
const [formState, { text, textarea }] = useFormState({
name: '',
message: ''
});
return (
<form>
<label>Name</label>
<input {...text('name')} />
<label>Message</label>
<textarea {...textarea('message')} />
<button>Send</button>
</form>
);
}
Users should be able to swipe images left and right on mobile and desktop.
react-use-gesture (via @use-gesture/react)import { useDrag } from '@use-gesture/react';
function Gallery() {
const [{ x }, set] = useState({ x: 0 });
const bind = useDrag(({ movement: [mx] }) => {
set({ x: mx });
});
return (
<div {...bind()} style={{ transform: `translateX(${x}px)` }}>
<img src="/slide1.jpg" alt="Slide" />
</div>
);
}
| Package | Primary Use Case | Maintenance Status | Complexity | Best For |
|---|---|---|---|---|
react-use | General Utilities (Sensors, Async, Storage) | β Active | Medium | Dashboards, Apps needing many small helpers |
react-use-form-state | Simple Form State | β Active | Low | Small forms, Quick prototypes |
react-use-gesture | Touch/Mouse Interactions | β
Active (as @use-gesture) | High | Drag-and-drop, Carousels, Games |
react-hooks | Legacy Utilities | β Deprecated | Low | None (Do Not Use) |
For modern development, your strategy should be selective:
react-hooks entirely. It is a dead end. The few utilities it offers are easily replicated or found in better-maintained libraries.react-use for infrastructure needs. If your app relies heavily on browser APIs (geolocation, local storage, media queries), this library saves significant development time and reduces bugs related to event listener cleanup.react-use-form-state only for simplicity. If your forms grow in complexity (requiring nested validation, dynamic fields, or server-side error mapping), switch to a dedicated form library like react-hook-form. Use this package only for trivial forms.@use-gesture/react for interactions. While the original react-use-gesture package works, the ecosystem has moved to the scoped @use-gesture packages for better tree-shaking and modularity. This is the industry standard for gesture-based UIs.By choosing actively maintained, specialized tools over monolithic or abandoned packages, you ensure your application remains secure, performant, and easy to refactor as React evolves.
Do NOT choose react-hooks for any new project. This package is deprecated and unmaintained, posing significant risks for security and compatibility with modern React versions. Instead, migrate to react-use for general utilities or build custom hooks tailored to your specific needs using the latest React documentation.
Choose react-use if you need a vast library of general-purpose hooks for sensors, lifecycle events, and async state management. It is ideal for projects where you want to avoid writing boilerplate hooks for common tasks like window resizing, local storage sync, or fetch handling, and you prefer a single dependency for many utilities.
Choose react-use-form-state if you need a tiny, zero-dependency solution strictly for managing simple form inputs. It is perfect for small forms where full-scale libraries like React Hook Form or Formik are overkill, offering a straightforward API to bind values, errors, and touched states without complex validation schemas.
Choose react-use-gesture (or its modern successor @use-gesture/react) if your application requires complex drag, pinch, scroll, or hover interactions with spring animations. It is the best choice for building interactive UIs like image carousels, draggable panels, or gesture-based games where precise pointer tracking and physics are critical.
Silly little component to fire off actions in stateless components.
$ npm install react-hooks
Build:
$ make build
Start dev server:
$ make start
tjholowaychuk.com Β Β·Β GitHub @tj Β Β·Β Twitter @tjholowaychuk