React Hooks Explained: What They Are and When to Use Them
A beginner-friendly guide to React hooks: what useState, useEffect, useRef and friends actually do, when to use each, and the rules that keep them working.
- →React hooks are functions that let function components use state and other React features without classes.
- →useState adds state; useEffect runs side effects; useRef holds a mutable value that doesn't trigger re-renders.
- →Only call hooks at the top level of a component, never inside loops, conditions or nested functions.
- →useMemo and useCallback cache values and functions to avoid unnecessary re-computation.
- →You can build your own custom hooks to reuse stateful logic across components.
React hooks changed how we write components. Before them, only class components could hold state, hooks let plain function components do everything. If you're learning React, understanding what hooks are used for, and which one to reach for, is the single most useful thing you can master.
What are React hooks used for?
React hooks are special functions that let function components 'hook into' React features like state, lifecycle and context, without writing a class. In short, they let a simple function component remember values, run side effects, and share logic. Every hook name starts with use (useState, useEffect, useRef), and React ships about a dozen built-in ones.
The hooks you'll use most
| Hook | What it's for | Reach for it when... |
|---|---|---|
| useState | Local component state | A value changes and the UI should update |
| useEffect | Side effects | Fetching data, subscriptions, timers, DOM sync |
| useRef | Mutable value / DOM node | You need a value that persists but shouldn't re-render |
| useContext | Read shared context | Avoiding prop-drilling across many components |
| useMemo | Cache a computed value | An expensive calculation re-runs too often |
| useCallback | Cache a function | Passing stable callbacks to memoized children |
useState: remembering values
useState is the hook you'll use first and most. It gives a component a piece of state and a setter. When you call the setter, React re-renders with the new value.
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
}useEffect: running side effects
useEffect runs code after render, for things that reach outside React: fetching data, setting up subscriptions, timers, or syncing with the DOM. The dependency array controls when it runs: empty means once on mount, with values means whenever those values change.
import { useEffect, useState } from "react";
function User({ id }) {
const [user, setUser] = useState(null);
useEffect(() => {
let active = true;
fetch(`/api/users/${id}`)
.then((r) => r.json())
.then((data) => { if (active) setUser(data); });
return () => { active = false; }; // cleanup
}, [id]); // re-run when id changes
return <p>{user?.name ?? "Loading..."}</p>;
}useState vs useEffect confusion is common: useState stores a value; useEffect reacts to values by running side effects. If you're updating the screen, that's state. If you're talking to the outside world, that's an effect.
useRef: a box that survives renders
useRef gives you a mutable container whose .current persists across renders but does not trigger a re-render when it changes. Two main uses: referencing a DOM node, and storing a value you want to remember without re-rendering (like a timer id or previous value).
import { useRef } from "react";
function TextInput() {
const inputRef = useRef(null);
return (
<>
<input ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>Focus</button>
</>
);
}The rules of hooks
Hooks work by call order, so React needs them called the same way every render. Two rules keep them reliable:
- 1.Only call hooks at the top level, never inside loops, conditions, or nested functions.
- 2.Only call hooks from React function components or from other custom hooks.
If you ever see 'Rendered fewer hooks than expected', you almost certainly called a hook inside an if. Move it to the top level and it's fixed.
useMemo and useCallback: caching
These two optimize performance by caching. useMemo caches the result of an expensive calculation; useCallback caches a function so it stays the same between renders. Reach for them only when you have a measured problem, premature memoization adds complexity for no gain.
Custom hooks: reuse your own logic
The real power of hooks is composition. Any function that starts with use and calls other hooks is a custom hook, letting you extract and reuse stateful logic across components.
function useLocalStorage(key, initial) {
const [value, setValue] = useState(
() => JSON.parse(localStorage.getItem(key)) ?? initial
);
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}The short version
React hooks let function components use state and other features without classes. Use useState for values that change, useEffect for side effects, useRef for values that persist without re-rendering, and custom hooks to reuse logic. Follow the two rules, only at the top level, only in components or hooks, and you'll avoid the common pitfalls.
Frequently asked questions
What are React hooks used for?+
React hooks let function components use state and other React features without writing a class. They're used to store state (useState), run side effects like data fetching (useEffect), reference DOM nodes or persistent values (useRef), read shared context (useContext), and reuse stateful logic through custom hooks.
What's the difference between useState and useEffect?+
useState stores a value in a component and re-renders the UI when that value changes. useEffect runs side effects, code that reaches outside React such as fetching data, subscriptions or timers, after render, and re-runs based on its dependency array. In short: useState holds data, useEffect reacts to it.
What are the rules of React hooks?+
Two rules: only call hooks at the top level of a component, never inside loops, conditions or nested functions; and only call hooks from React function components or from other custom hooks. These rules exist because React tracks hooks by call order.
What is useRef used for in React?+
useRef creates a mutable container whose .current value persists across renders without causing a re-render when it changes. It's used to reference a DOM node (for example, to focus an input) or to store a value you want to remember between renders, like a timer id or the previous value.
What is a custom React hook?+
A custom hook is a JavaScript function whose name starts with 'use' and which calls other hooks. It lets you extract and reuse stateful logic across multiple components, for example a useLocalStorage or useFetch hook, keeping components clean and logic shareable.
I build fast, SEO-ready sites and rank them on Google and AI search.