Hooks
Hooks are functions such as useState and useEffect; their names start
with use. They give function components access to React features: state,
effects, context, refs. There are two rules: call hooks only at the top
level (not in conditions, loops, nested functions or after an early return)
and only from React functions (components and custom hooks). The reason is
that React matches a hook call with its stored state by the order of calls.
Applies to: React 19.3.
Details
Built-in Hooks
| Hook | Purpose | Page |
|---|---|---|
useState | State of a component | State |
useReducer | State with update logic in a reducer | State |
useContext | Read a context value | Context |
useRef | A mutable value that does not cause re-renders; access to DOM nodes | Refs |
useImperativeHandle | Customize what a ref to the component exposes | Refs |
useEffect | Synchronize with an external system after render | Side Effects |
useLayoutEffect | The same, but before the browser paints | Side Effects |
useInsertionEffect | Insert styles before layout effects; for CSS-in-JS libraries | — |
useEffectEvent | A function that reads the latest props and state inside an effect | Side Effects |
useMemo | Cache a computed value between renders | Optimization |
useCallback | Cache a function between renders | Optimization |
useTransition | Mark a state update as non-urgent | Concurrent Rendering |
useDeferredValue | A value that lags behind during urgent updates | Concurrent Rendering |
useId | A unique ID that is the same on the server and the client | — |
useSyncExternalStore | Subscribe to a store outside of React | — |
useActionState | State and pending flag of an Action | Forms |
useOptimistic | Show the expected result while an Action is pending | Forms |
useFormStatus | Status of the parent <form> (from react-dom) | Forms |
use | Read a promise or a context. An API, not a hook: allowed in if | Concurrent Rendering |
Rules of Hooks
- Only call hooks at the top level. React keeps the hooks of a component in a list and finds each one by its position. If a call is skipped, every hook after it gets the wrong state.
- Only call hooks from React functions: function components and custom hooks. Not from regular functions, class components or event handlers.
useis an API, not a hook, so the first rule does not apply to it: it can be called in a condition or a loop, but still only inside a component or a hook.- The rules are checked by
eslint-plugin-react-hooks.
Custom Hooks
- A custom hook is a function named
use…that calls other hooks. - It shares logic, not state: every component that calls the hook gets its own independent state.
- It replaces HOCs and render props and can be tested separately from the UI.
- A function that calls no hooks should not be named
use….
Example
A condition goes inside the hook, not around it:
import { useEffect } from 'react';
function Chat({ roomId, isOnline }) {
// Wrong: the hook is skipped on some renders
if (isOnline) {
useEffect(() => connect(roomId), [roomId]);
}
// Right: the hook is always called, the condition is inside
useEffect(() => {
if (!isOnline) {
return;
}
return connect(roomId);
}, [roomId, isOnline]);
return <p>Room: {roomId}</p>;
}
A custom hook:
- useToggle.js
- ToggleButton.jsx
import { useCallback, useState } from 'react';
export default function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = useCallback(() => {
setValue((prevValue) => !prevValue);
}, []);
return [value, toggle];
}
import useToggle from './useToggle';
export default function ToggleButton() {
const [isOn, toggleIsOn] = useToggle(false);
return <button onClick={toggleIsOn}>{isOn ? 'ON' : 'OFF'}</button>;
}
Follow-up Questions
- What problems did hooks solve? Stateful logic is reused without HOCs and
render props (no "wrapper hell"), a component's logic is split by concern
instead of by lifecycle method, and there is no
this. - Why can't hooks be called conditionally? React identifies a hook by its call order, not by a name.
- Do two components that use the same custom hook share state? No. To share state, lift it up or use context or a store.
- Can hooks be used in class components? No. A class can be wrapped in a function component that calls the hook and passes the result as props.
Common Mistakes
- An early
returnabove a hook call. - Calling a hook inside a callback, an event handler or
useMemo. - Giving "not in conditions" and "not in loops" as the two rules: that is one rule; the second one is about where hooks can be called from.