React Hooks
Hooks are functions that let you use React features inside functional components. With hooks, you can manage state, handle side effects, access context, and more, all without writing a class.
Before hooks arrived in React 16.8, you needed a class component any time you wanted to store state or respond to lifecycle events. Hooks changed that. Now a simple function can do everything a class could do, with less boilerplate and easier testing.
Rules of Hooks
There are two rules you must follow when using hooks. These are not arbitrary. Breaking them causes bugs that are hard to trace.
Rule 1: Only call hooks at the top level.
Do not call hooks inside loops, conditions, or nested functions.
// Correct
function MyComponent() {
const [count, setCount] = useState(0);
// ...
}
// Wrong: hook inside a condition
function MyComponent({ shouldTrack }) {
if (shouldTrack) {
const [count, setCount] = useState(0); // Don't do this
}
}
React tracks hooks by the order they are called. If you put a hook inside a condition, that order can change between renders, and React loses track of which state belongs to which hook call.
Rule 2: Only call hooks inside React functional components or other custom hooks.
Do not call hooks from plain JavaScript functions, class components, or event handlers defined outside a component.
// Correct: inside a functional component
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
// Wrong: inside a plain function
function doSomething() {
const [value, setValue] = useState(''); // Don't do this
}
This rule exists because React needs to know which component a hook belongs to, so it can store the right state and clean up effects at the right time.
Built-in Hooks
React ships with several built-in hooks. Here are the ones you will use most often.
State and data
Store a value inside a component. When the value changes, React re-renders the component.
const [count, setCount] = useState(0);
Manage more complex state with a reducer function. Useful when multiple state values update together or when the update logic is complex.
const [state, dispatch] = useReducer(reducer, initialState);
Side effects
Run code after a component renders. Use it to fetch data, set up subscriptions, or interact with the DOM.
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
DOM and persistence
Access a DOM element directly, or store a value that persists between renders without causing a re-render.
const inputRef = useRef(null);
Performance
Cache the result of an expensive calculation so it only re-runs when its dependencies change.
const filtered = useMemo(() => list.filter(item => item.active), [list]);
Cache a function so it is not recreated on every render. Useful when passing callbacks to child components that rely on reference equality.
const handleClick = useCallback(() => {
doSomething(id);
}, [id]);
Context
useContext
Read a value from a React context without wrapping your component in a Consumer.
const theme = useContext(ThemeContext);
Concurrency
Mark a state update as non-urgent so React can keep the UI responsive while processing it.
const [isPending, startTransition] = useTransition();
startTransition(() => setFilteredList(filter(query)));
useDeferredValue (also on the useTransition page )
Defer a value you received from outside so an expensive render does not block the UI.
const deferredQuery = useDeferredValue(query);
Custom Hooks
You can build your own hooks by combining built-in ones. A custom hook is just a function whose name starts with use. It can call other hooks internally.
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return width;
}
Any component can then call useWindowWidth() to get the current browser width, without duplicating the resize logic.
What to learn next
- useState : the most commonly used hook
- useEffect : how to handle side effects like data fetching
- useMemo : when and how to optimise expensive calculations
- useRef : accessing DOM elements and persisting values
- useReducer : managing complex state transitions
- useCallback : stabilising function references for memoised children
- Custom Hooks : writing your own reusable hooks
- useTransition : keeping the UI responsive during slow renders
For the full hooks reference, see the React docs on hooks .