React hooks simplify the way we manage state, side effects, and logic in functional components. But with so many hooks—useState
, useEffect
, useRef
, and more—developers often ask: "Which hook should I use, and when?"
This guide explains the most commonly used hooks in React, when to use them, and how they work — all with clear examples. Let's dive in! 🚀
1️⃣ useState
– For Simple Local State
✅ Use When
You need to manage simple local state like numbers, strings, booleans, arrays, or objects.
🧠 Example
const [count, setCount] = useState(0);
📝 Use case: Counter, form inputs, toggles.
2️⃣ useReducer
– For Complex State Logic
✅ Use When
- You have multiple related state values
- State transitions are more complex (like with Redux-style actions)
🧠 Example
const [state, dispatch] = useReducer(reducer, initialState);
📝 Use case: Forms with validations, shopping carts, toggles with logic.
3️⃣ useEffect
– For Side Effects
✅ Use When
You need to perform actions after render, such as:
- Fetching data
- Subscribing to events
- Changing the DOM
🧠 Example
useEffect(() => { fetchData(); }, []);
📝 Use case: API calls, event listeners, local storage access.
4️⃣ useRef
– For DOM Access and Persistent Variables
✅ Use When
- You need a reference to a DOM element
- You want to persist a value without triggering re-renders
🧠 Example
const inputRef = useRef(null);
📝 Use case: Managing focus, storing previous values, and measuring DOM nodes.
5️⃣ useMemo
– For Expensive Computations
✅ Use When
You want to memoize a computed value so it's not recalculated unnecessarily on every render.
🧠 Example
const total = useMemo(() => computeTotal(items), [items]);
📝 Use case: Filtering large lists, heavy calculations.
6️⃣ useCallback
– For Memoized Functions
✅ Use When
You want to prevent functions from being recreated unless dependencies change, especially when passing functions to child components.
🧠 Example
const handleClick = useCallback(() => { doSomething(); }, []);
📝 Use case: Avoid unnecessary re-renders in child components.
7️⃣ useContext
– For Global or Shared State
✅ Use When
You want to share data globally (like theme, language, user auth) without prop drilling.
🧠 Example
const theme = useContext(ThemeContext);
📝 Use case: Authentication state, themes, localization.
8️⃣ useLayoutEffect
– For Layout Changes Before Paint
✅ Use When
You need to read the layout and re-render before the browser paints.
🧠 Example
useLayoutEffect(() => { const height = ref.current.clientHeight; }, []);
📝 Use case: Measuring DOM, animations, positioning.
9️⃣ useImperativeHandle
– For Exposing Custom Functions via Ref
✅ Use When
You want to expose imperative methods from a child component to its parent using ref
.
🧠 Example
useImperativeHandle(ref, () => ({ focus: () => inputRef.current.focus() }));
📝 Use case: Exposing .open()
, .focus()
methods from a custom modal or input.
🔟 Custom Hooks – For Reusable Logic
✅ Use When
You want to extract reusable logic across multiple components.
🧠 Example
function useAuth() { const [user, setUser] = useState(null); return { user, login, logout }; }
📝 Use case: useAuth
, useForm
, useFetch
, useTheme
.
📌 Final Cheat Sheet
Purpose |
Hook |
Simple state |
useState |
Complex/multiple state |
useReducer |
Side effects (API, subscriptions) |
useEffect |
DOM access or persistent ref |
useRef |
Memoized value |
useMemo |
Memoized function |
useCallback |
Global/shared state |
useContext |
DOM layout measurement |
useLayoutEffect |
Expose functions via ref |
useImperativeHandle |
Reusable custom logic |
Custom Hook |
✅ Conclusion
React hooks are powerful, but choosing the right hook at the right time makes all the difference in writing clean, maintainable code.
Whether you're building a simple to-do app or a complex dashboard, this guide helps you choose wisely.