React Hooks Reference

Complete React Hooks guide with TypeScript examples. Click any hook to expand its full code example and usage tips.

22 of 22 hooks — click any card to expand the code example

Rules of Hooks

React relies on the order in which Hooks are called to associate each hook call with the correct state between renders. This is why there are two fundamental rules. First, only call Hooks at the top level of a function component or custom Hook — never inside loops, if statements, or nested functions. Second, only call Hooks from React function components or custom Hooks — not from regular utility functions, class components, or event handlers.

If you need to conditionally run an effect, put the condition inside the Hook rather than putting the Hook inside the condition. For example, instead of if (isLoggedIn) useEffect(...), write useEffect(() => { if (isLoggedIn) { ... } }, [isLoggedIn]). The eslint-plugin-react-hooks package enforces both rules automatically and should be part of every React project's toolchain.

Performance Hooks (useMemo & useCallback)

Both useMemo and useCallback cache values between renders, but they serve different purposes. useMemo caches the result of calling a function — use it for expensive calculations such as filtering a large array or computing derived data. useCallback caches the function itself — use it to maintain a stable reference when passing callbacks to memoised children or listing a function in a useEffect dependency array.

The critical insight is that both are only useful in combination with other optimisations. useCallback has no effect unless the child is wrapped in React.memo. Memoizing a cheap calculation with useMemo adds overhead without benefit. The React team's guidance: profile first, then optimize. React Compiler (introduced in React 19) automates most of these optimizations, reducing the need to reach for these hooks manually.

Custom Hook Patterns

Custom Hooks are the primary way to share stateful logic between components in React. A custom Hook is any function that starts with use and calls other Hooks inside it. Unlike render props and higher-order components, custom Hooks don't add extra nodes to the component tree — the logic is extracted, but the state lives in the calling component.

Good candidates for custom Hooks are: logic that appears in multiple components (useDebounce, useFetch), browser API subscriptions (useWindowSize, useOnlineStatus), and complex state machines that would clutter a component. Keep custom Hooks small and focused on a single concern — composing two smaller hooks is always better than one large hook with many responsibilities. Export the return value as as const from tuple-returning hooks so TypeScript infers the correct tuple type instead of a union array.

Frequently Asked Questions

What are the rules of React Hooks?

There are two core rules. First, only call Hooks at the top level of a React function — never inside loops, conditions, or nested functions. This ensures React can track hooks in the same order on every render. Second, only call Hooks from React function components or custom Hooks — not from regular JavaScript functions, class components, or event handlers. The eslint-plugin-react-hooks package (included in Create React App and most frameworks) enforces both rules automatically.

What is the difference between useEffect and useLayoutEffect?

Both accept the same arguments and work the same way, but they fire at different times in the render cycle. useEffect fires asynchronously after the browser has painted — it doesn't block the visual update, making it suitable for data fetching, subscriptions, and most side effects. useLayoutEffect fires synchronously after all DOM mutations but before the browser paints. Use it when you need to read DOM layout (e.g., element dimensions) and synchronously update the DOM to avoid a visual flicker — for example, positioning a tooltip or measuring a container. For SSR, useLayoutEffect produces a warning because it doesn't run on the server; useEffect is safe in both environments.

When should I use useMemo and useCallback?

Both are performance optimizations that you should add only after measuring a real performance problem, not upfront. useMemo caches the result of an expensive computation and recomputes only when its dependencies change — use it for heavy calculations like filtering or sorting large arrays. useCallback caches a function reference and is most useful when you pass a callback to a child component wrapped in React.memo, or when a function is in a useEffect dependency array. If a child is not memoised, useCallback provides no benefit because the child re-renders regardless. Remember: memoization itself has a cost (memory and comparison), so overusing these hooks can make your app slower, not faster.

How do I write a custom React Hook?

A custom Hook is simply a JavaScript function whose name starts with 'use' and that calls other Hooks inside it. This naming convention tells React's linter to enforce the rules of Hooks on your function. Custom Hooks let you extract stateful logic that can be shared across components without changing the component tree — no render props or higher-order components needed. Common patterns include useLocalStorage (persist state to localStorage), useDebounce (delay a value update), useFetch (data fetching with loading/error states), and useWindowSize (responsive layout). Each custom Hook has its own isolated state — two components using the same custom Hook don't share state.

What new hooks were added in React 18?

React 18 introduced several new hooks. useId generates stable, unique IDs safe for server-side rendering — solving the common hydration mismatch from counter-based ID generation. useTransition and useDeferredValue support concurrent rendering: useTransition lets you mark a state update as non-urgent so React can interrupt it for higher-priority updates (like typing), while useDeferredValue defers updating a value until React is idle. useSyncExternalStore is the recommended way to subscribe to external stores (browser APIs, third-party state managers) in a concurrent-safe way. useInsertionEffect is a low-level hook for CSS-in-JS library authors to inject styles before layout effects run.