5 min to read
React Hooks have revolutionized modern frontend development. By simplifying state management, side effects, and reusable logic, Hooks enable developers to write cleaner, more modular, and maintainable components.
In this guide, we explore the best 20 React Hooks—including both built-in and custom hooks—that power the vast majority of React applications today.
useState
The useState
hook adds local state to functional components.
Use cases: Form inputs, toggles, counters, local UI state.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
);
}
Why it matters: Most interactive components depend on useState
for internal logic.
useEffect
Handles side effects such as data fetching, event listeners, and DOM manipulation.
Use cases: API calls, subscriptions, timers.
import { useEffect } from 'react';
useEffect(() => {
document.title = "React App";
return () => {
// Cleanup
};
}, []);
Why it matters: Connects components to the outside world—essential for real apps.
useRef
Creates a mutable reference that persists across renders without causing re-renders.
Use cases: Accessing DOM nodes, timers, storing previous state.
import { useRef } from 'react';
function InputFocus() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>Focus</button>
</>
);
}
Why it matters: Bridges the gap between React and the DOM.
useCallback
Returns a memoized version of a function to avoid re-creating it on every render.
Use cases: Stable event handlers, performance optimizations.
import { useCallback } from 'react';
const handleClick = useCallback(() => {
// Expensive operation
}, []);
Why it matters: Prevents unnecessary re-renders in child components.
useMemo
Memoizes the result of an expensive computation.
Use cases: Derived state, filtering, performance tuning.
import { useMemo } from 'react';
const filteredList = useMemo(() => {
return list.filter(item => item.active);
}, [list]);
Why it matters: Boosts performance by avoiding redundant calculations.
useContext
Accesses values from React’s Context API to avoid prop drilling.
Use cases: Themes, auth, localization.
import { useContext } from 'react';
import { ThemeContext } from './ThemeContext';
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>Click me</button>;
}
Why it matters: Simplifies global state access.
useId
Generates a unique ID for accessibility and hydration consistency.
Use cases: Label/input associations, SSR-safe IDs.
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
return (
<>
<input aria-describedby={passwordHintId} />
<div id={passwordHintId}>Password must be at least 8 characters.</div>
</>
);
}
Why it matters: Prevents ID collisions across renders and servers.
useReducer
Alternative to useState
for complex or interdependent state logic.
Use cases: Forms, state machines, toggles with logic.
import { useReducer } from 'react';
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<button onClick={() => dispatch({ type: 'increment' })}>
Count: {state.count}
</button>
);
}
Why it matters: Enables structured, testable state transitions.
useImperativeHandle
Customizes values exposed to parent components using ref
.
Use cases: Exposing methods like focus()
from child to parent.
import { useImperativeHandle, forwardRef, useRef } from 'react';
const FancyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus()
}));
return <input ref={inputRef} />;
});
Why it matters: Enables parent-child communication via imperative APIs.
useLayoutEffect
Runs synchronously after DOM mutations and before painting.
Use cases: DOM measurements, animations.
import { useLayoutEffect, useRef } from 'react';
function LayoutComponent() {
const divRef = useRef();
useLayoutEffect(() => {
// Measure layout
}, []);
return <div ref={divRef}>Content</div>;
}
Why it matters: Useful for precise layout control.
useDebugValue
Displays custom hook values in React DevTools.
Use cases: Debugging custom hooks.
import { useDebugValue } from 'react';
function useFriendStatus(friendID) {
const isOnline = useFriendStatusAPI(friendID);
useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}
Why it matters: Improves transparency for debugging.
useDeferredValue
Defers non-urgent state updates for smoother UI.
Use cases: Search inputs, expensive re-renders.
import { useDeferredValue } from 'react';
function SearchResults({ query }) {
const deferredQuery = useDeferredValue(query);
// Render based on deferredQuery
}
Why it matters: Enhances perceived performance.
useTransition
Marks state updates as non-urgent to avoid blocking interactions.
Use cases: Large UI updates, pagination.
import { useTransition } from 'react';
function App() {
const [isPending, startTransition] = useTransition();
const handleClick = () => {
startTransition(() => {
// Trigger heavy update
});
};
return <button onClick={handleClick}>Update</button>;
}
Why it matters: Keeps the UI responsive during updates.
useSyncExternalStore
Subscribes to external data sources in a concurrent-safe way.
Use cases: Redux-like stores, subscriptions.
import { useSyncExternalStore } from 'react';
function useExternalStore(store) {
return useSyncExternalStore(
store.subscribe,
store.getSnapshot,
store.getServerSnapshot
);
}
Why it matters: Ensures consistency with concurrent rendering.
useInsertionEffect
Injects styles before DOM changes. Ideal for CSS-in-JS libraries.
Use cases: Runtime style injection.
import { useInsertionEffect } from 'react';
function StyleInjector() {
useInsertionEffect(() => {
// Inject CSS here
}, []);
return null;
}
Why it matters: Prevents layout shifts from dynamic styles.
useBoolean
(Custom)Simplifies boolean state toggles.
Use cases: Modal visibility, switches.
function useBoolean(initialValue = false) {
const [value, setValue] = useState(initialValue);
const setTrue = () => setValue(true);
const setFalse = () => setValue(false);
const toggle = () => setValue(v => !v);
return [value, { setTrue, setFalse, toggle }];
}
Why it matters: Reduces boilerplate.
usePrevious
(Custom)Tracks the previous value of a prop or state.
Use cases: Comparing values, tracking changes.
import { useRef, useEffect } from 'react';
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
Why it matters: Adds history to stateful logic.
useFetch
(Custom)Simplifies data fetching logic into a reusable hook.
Use cases: API calls, data loading.
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch(url)
.then(res => res.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [url]);
return { data, loading, error };
}
Why it matters: Encapsulates fetching logic into clean reusable code.
useEventListener
(Custom)Attaches and cleans up event listeners.
Use cases: Resize events, keyboard shortcuts.
import { useEffect } from 'react';
function useEventListener(event, handler, element = window) {
useEffect(() => {
element.addEventListener(event, handler);
return () => element.removeEventListener(event, handler);
}, [event, handler, element]);
}
Why it matters: Ensures proper cleanup and reattachment.
useLocalStorage
(Custom)Synchronizes state with localStorage.
Use cases: Persisting preferences, tokens.
import { useState } from 'react';
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
const setValue = value => {
setStoredValue(value);
window.localStorage.setItem(key, JSON.stringify(value));
};
return [storedValue, setValue];
}
Why it matters: Adds persistence with minimal effort.
Hook | Use Case | Common Example |
---|---|---|
useState |
Local state | Counters, toggles |
useEffect |
Side effects | Fetching data |
useRef |
Mutable reference, DOM access | Input focus, timers |
useCallback |
Stable function reference | Event handlers |
useMemo |
Memoized computation | Filtered lists |
useContext |
Global/shared state | Themes, auth contexts |
useId |
Unique ID generation | Form fields, SSR |
useReducer |
Complex state transitions | Form logic |
useImperativeHandle |
Expose methods via ref |
Trigger methods on children |
useLayoutEffect |
Synchronous layout effects | Animations, DOM reads |
Mastering these 20 React Hooks—both core and custom—will dramatically improve how you structure and scale your React applications. They cover 90% of the real-world use cases in modern component design, offering performance, clarity, and reusability out of the box.
Connect with top remote developers instantly. No commitment, no risk.
Tags
Discover our most popular articles and guides
Running Android emulators on low-end PCs—especially those without Virtualization Technology (VT) or a dedicated graphics card—can be a challenge. Many popular emulators rely on hardware acceleration and virtualization to deliver smooth performance.
The demand for Android emulation has soared as users and developers seek flexible ways to run Android apps and games without a physical device. Online Android emulators, accessible directly through a web browser.
Discover the best free iPhone emulators that work online without downloads. Test iOS apps and games directly in your browser.
Top Android emulators optimized for gaming performance. Run mobile games smoothly on PC with these powerful emulators.
The rapid evolution of large language models (LLMs) has brought forth a new generation of open-source AI models that are more powerful, efficient, and versatile than ever.
ApkOnline is a cloud-based Android emulator that allows users to run Android apps and APK files directly from their web browsers, eliminating the need for physical devices or complex software installations.
Choosing the right Android emulator can transform your experience—whether you're a gamer, developer, or just want to run your favorite mobile apps on a bigger screen.
The rapid evolution of large language models (LLMs) has brought forth a new generation of open-source AI models that are more powerful, efficient, and versatile than ever.