Runnable lesson · press Try it on the examples to edit and run them here.
You have met useState, useEffect, useRef, useMemo, useCallback and useContext. React has more built-in hooks. This lesson is a map, so you know what exists and when to look.
Hooks you will use often later
| Hook | What it does | Where this course covers it |
|---|---|---|
useReducer | State with an update function (a reducer) for complex logic | Reducers and useReducer |
useId | Creates a unique, stable id for labels and accessibility | below |
use | Reads a promise or a context during render | Suspense |
useActionState | State for a form action, with a pending flag | Form Actions |
useTransition | Marks a state update as non-urgent | Performance Optimization |
useDeferredValue | Lets part of the UI lag behind a fast-changing value | Performance Optimization |
useId: unique ids for labels
Never write the same id twice on one page, and never generate random ids during render. useId gives a stable id that is the same on the server and the client:
function Field({ label }) {
const id = React.useId();
return (
<div>
<label htmlFor={id}>{label}</label>{" "}
<input id={id} aria-label={label} />
</div>
);
}
function App() {
// Two Fields on one page get two different ids
return (
<div>
<Field label="Email" />
<Field label="Backup email" />
</div>
);
}
Do not use useId for list keys.
useReducer in a nutshell
function reducer(state, action) {
switch (action.type) {
case "increment": return { count: state.count + 1 };
case "reset": return { count: 0 };
default: throw new Error("Unknown action: " + action.type);
}
}
function App() {
const [state, dispatch] = React.useReducer(reducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "reset" })}>Reset</button>
</div>
);
}
You describe what happened (dispatch), and the reducer decides the new state. The full story is in Reducers and useReducer.
useLayoutEffect
Like useEffect, but it runs before the browser paints. Use it when you must measure the DOM and change something before the user sees the first frame (a tooltip position, for example). It blocks painting, so use it only when useEffect causes a visible flicker.
useTransition and useDeferredValue
Both help keep the UI responsive during slow updates. useTransition marks an update as low priority, and gives you isPending; useDeferredValue gives a “lagging” copy of a value. See Performance Optimization.
useEffectEvent (React 19.2)
Sometimes an effect needs to read the latest props or state without re-running when they change, for example logging a visit using the current theme. useEffectEvent creates a function that always sees the latest values but is not a dependency of the effect:
const onConnected = useEffectEvent(() => {
showNotification("Connected!", theme); // always the latest theme
});
useEffect(() => {
const connection = createConnection(roomId);
connection.on("connected", () => onConnected());
connection.connect();
return () => connection.disconnect();
}, [roomId]); // theme is not needed here
It was added as a stable API in React 19.2. Use it only inside effects, and only to reduce unnecessary re-runs; it is not a general-purpose callback.
useSyncExternalStore
Subscribes to an external store (a global data object, the browser’s online status) in a way that is safe with React’s rendering. Libraries use it; you rarely call it yourself.
useImperativeHandle, useDebugValue, useInsertionEffect
useImperativeHandlecustomises what a parent can do with a child’s ref (rare).useDebugValuelabels a custom hook in React DevTools.useInsertionEffectis for CSS-in-JS libraries to inject styles. Application code does not need it.
Hooks that are not in react
useFormStatus(fromreact-dom): the pending state of the form it is inside.useOptimistic(fromreact): show a result immediately while the real update is in progress.
Key points
- Know the names:
useReducer,useId,useTransition,useDeferredValue,use,useActionState,useEffectEvent. - Reach for them when
useStateanduseEffectstart to feel awkward. - Most apps need only a handful of hooks.