# Understanding Hooks

Course: [React](https://www.devtutorials.ai/learn/react) · Section: React Hooks
Source: https://www.devtutorials.ai/learn/react/hooks/understanding-hooks

> What hooks are, their benefits and rules, when to use them, the five groups of built-in hooks, a tour of useState, useEffect, useRef, useContext, useReducer, useMemo and useCallback, and how to choose the right one.

## Introduction to Hooks

A **hook** is a special React function that gives a component an extra power, such as remembering a value or running code after the screen updates. Every hook's name starts with `use`.

You have already used one hook: `useState`. It gives a component the power to remember a value. React has more hooks, and each one gives a different power.

### Real-World Example

A bookshop's book page must remember how many copies the user selected. A normal variable is reset every time the component runs again, so the number is lost.

The component calls the hook `useState(1)`. React keeps the number between renders, and the page shows the new quantity each time the user clicks **+**.

A hook is a function whose name starts with `use`. You call it inside a component to give the component a new power.

## Benefits of Hooks

Before hooks, many React powers were only available in **class components**, which were longer and harder to read. Hooks bring the same powers to normal function components.

- **Shorter code** — Function components with hooks need less code than classes.
- **Easier to read** — Code for one job sits together, not split across many places.
- **Reusable logic** — You can move hook code into your own hook and share it. You will learn this in the next lesson.
- **Easier to test** — Small functions are easier to check than big classes.

## Rules of Hooks

Hooks must follow two rules. If you break them, React can mix up your hooks and show wrong data.

### Rule 1: Call Hooks Only at the Top Level

Call hooks at the top of your component. **Do not** call them inside an `if`, a loop, or a nested function.

```tsx
// Wrong: the hook is inside an if
if (isLoggedIn) {
  const [name, setName] = useState("");
}

// Right: the hook is at the top. Use the if later.
const [name, setName] = useState("");
if (isLoggedIn) {
  // use name here
}
```

React remembers hooks by their **order**: the first `useState`, the second `useState`, and so on. If a hook is inside an `if`, it may be skipped on some renders. Then the order changes, and React gives the wrong value to the wrong hook.

### Rule 2: Call Hooks Only from React Functions

Call hooks only inside:

- a **component** (a function whose name starts with a capital letter), or
- a **custom hook** (a function whose name starts with `use`).

Do not call hooks inside a normal JavaScript function.

Easy way to remember: hooks go at the **top** of a **component** or **custom hook**. Nowhere else.

## Built-in Hook Categories

React's built-in hooks fall into five groups, based on what they do.

<figure className="react-fig">
<svg viewBox="0 0 520 200" role="img" aria-labelledby="fig-hookcats-title" style={{ width: "100%", maxWidth: 520, height: "auto" }}>
  <title id="fig-hookcats-title">Five groups of hooks: State (useState, useReducer), Effect (useEffect), Reference (useRef), Context (useContext), Performance (useMemo, useCallback)</title>
  <g style={{ fontFamily: "var(--sans)" }}>
    <rect x="10" y="20" width="92" height="160" rx="10" style={{ fill: "var(--accent-soft)", stroke: "var(--accent)" }} />
    <text x="56" y="48" textAnchor="middle" style={{ fill: "var(--accent)", fontSize: 14, fontWeight: 700 }}>State</text>
    <text x="56" y="90" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--mono)" }}>useState</text>
    <text x="56" y="110" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--mono)" }}>useReducer</text>
    <rect x="112" y="20" width="92" height="160" rx="10" style={{ fill: "var(--accent-secondary-soft)", stroke: "var(--accent-secondary)" }} />
    <text x="158" y="48" textAnchor="middle" style={{ fill: "var(--accent-secondary)", fontSize: 14, fontWeight: 700 }}>Effect</text>
    <text x="158" y="90" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--mono)" }}>useEffect</text>
    <rect x="214" y="20" width="92" height="160" rx="10" style={{ fill: "var(--ok-soft)", stroke: "var(--ok)" }} />
    <text x="260" y="48" textAnchor="middle" style={{ fill: "var(--ok)", fontSize: 14, fontWeight: 700 }}>Reference</text>
    <text x="260" y="90" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--mono)" }}>useRef</text>
    <rect x="316" y="20" width="92" height="160" rx="10" style={{ fill: "var(--info-soft)", stroke: "var(--info)" }} />
    <text x="362" y="48" textAnchor="middle" style={{ fill: "var(--info)", fontSize: 14, fontWeight: 700 }}>Context</text>
    <text x="362" y="90" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--mono)" }}>useContext</text>
    <rect x="418" y="20" width="92" height="160" rx="10" style={{ fill: "var(--panel2)", stroke: "var(--faint)" }} />
    <text x="464" y="48" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 13, fontWeight: 700 }}>Performance</text>
    <text x="464" y="90" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--mono)" }}>useMemo</text>
    <text x="464" y="110" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--mono)" }}>useCallback</text>
  </g>
</svg>
<figcaption>The five groups of built-in hooks, and the common hooks in each group.</figcaption>
</figure>

### State Hooks

**State hooks** let a component remember data that changes the screen. They are `useState` and `useReducer`.

### Effect Hooks

**Effect hooks** run code after React updates the screen, for work outside React. Examples: loading data, starting a timer, or changing the page title. The main one is `useEffect`.

### Reference Hooks

**Reference hooks** remember a value **without** updating the screen when it changes. They can also hold a link to a real element on the page. The main one is `useRef`.

### Context Hooks

**Context hooks** read data that is shared by many components, without passing props through every level. The main one is `useContext`.

### Performance Hooks

**Performance hooks** help React skip work that is not needed, so the app stays fast. They are `useMemo` and `useCallback`.

## Common Hooks Overview

This section shows each common hook in a short example.

### `useState`

`useState` remembers a value. When you change it with the set function, React updates the screen. You learned it in the State lesson.

<figure className="react-fig">
<svg viewBox="0 30 520 64" role="img" aria-labelledby="fig-h-state" style={{ width: "100%", maxWidth: 520, height: "auto" }}>
  <title id="fig-h-state">useState: count is 0, setCount(1) saves 1, React re-renders, the screen shows 1</title>
  <rect x="10" y="40" width="130" height="44" rx="8" style={{ fill: "var(--accent-soft)", stroke: "var(--accent)", strokeWidth: 1.5 }} />
  <text x="75.0" y="59.0" textAnchor="middle" style={{ fill: "var(--accent)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>count = 0</text>
  <text x="75.0" y="76.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>the value now</text>
  <path d="M140 62 L190 62" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M190 62 L181.7 65.5 L181.7 58.5 Z" style={{ fill: "var(--faint)" }} />
  <rect x="195" y="40" width="130" height="44" rx="8" style={{ fill: "var(--accent-secondary-soft)", stroke: "var(--accent-secondary)", strokeWidth: 1.5 }} />
  <text x="260.0" y="59.0" textAnchor="middle" style={{ fill: "var(--accent-secondary)", fontSize: 13, fontWeight: 700, fontFamily: "var(--mono)" }}>setCount(1)</text>
  <text x="260.0" y="76.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>save a new value</text>
  <path d="M325 62 L375 62" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M375 62 L366.7 65.5 L366.7 58.5 Z" style={{ fill: "var(--faint)" }} />
  <rect x="380" y="40" width="130" height="44" rx="8" style={{ fill: "var(--ok-soft)", stroke: "var(--ok)", strokeWidth: 1.5 }} />
  <text x="445.0" y="59.0" textAnchor="middle" style={{ fill: "var(--ok)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Screen shows 1</text>
  <text x="445.0" y="76.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>React re-renders</text>
  <circle r="6" style={{ fill: "var(--accent-secondary)" }}>
    <animateMotion dur="2.4s" repeatCount="indefinite" path="M140 62 L190 62 M325 62 L375 62" />
  </circle>
</svg>
<figcaption>useState keeps a value. Calling the set function saves a new value, and React shows it.</figcaption>
</figure>

```tsx
const [count, setCount] = useState(0);
```

### `useEffect`

`useEffect` runs code **after** React shows the component on the screen. You give it a function, and a list of values to watch, called the **dependency array**.

<figure className="react-fig">
<svg viewBox="0 30 520 64" role="img" aria-labelledby="fig-h-effect" style={{ width: "100%", maxWidth: 520, height: "auto" }}>
  <title id="fig-h-effect">useEffect runs after React renders and updates the screen</title>
  <rect x="10" y="40" width="140" height="44" rx="8" style={{ fill: "var(--accent-soft)", stroke: "var(--accent)", strokeWidth: 1.5 }} />
  <text x="80.0" y="59.0" textAnchor="middle" style={{ fill: "var(--accent)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>1. Render</text>
  <text x="80.0" y="76.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>run the component</text>
  <path d="M150 62 L186 62" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M186 62 L177.7 65.5 L177.7 58.5 Z" style={{ fill: "var(--faint)" }} />
  <rect x="190" y="40" width="140" height="44" rx="8" style={{ fill: "var(--ok-soft)", stroke: "var(--ok)", strokeWidth: 1.5 }} />
  <text x="260.0" y="59.0" textAnchor="middle" style={{ fill: "var(--ok)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>2. Update screen</text>
  <text x="260.0" y="76.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>show the new TSX</text>
  <path d="M330 62 L366 62" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M366 62 L357.7 65.5 L357.7 58.5 Z" style={{ fill: "var(--faint)" }} />
  <rect x="370" y="40" width="140" height="44" rx="8" style={{ fill: "var(--accent-secondary-soft)", stroke: "var(--accent-secondary)", strokeWidth: 1.5 }} />
  <text x="440.0" y="59.0" textAnchor="middle" style={{ fill: "var(--accent-secondary)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>3. Run effect</text>
  <text x="440.0" y="76.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>your useEffect code</text>
  <circle r="6" style={{ fill: "var(--accent-secondary)" }}>
    <animateMotion dur="3s" repeatCount="indefinite" path="M80 62 L186 62 L366 62 L440 62" />
  </circle>
</svg>
<figcaption>Effects run last: after React renders and updates the screen.</figcaption>
</figure>

      <p>Books in cart: {count}</p>
      <button onClick={() => setCount(count + 1)}>Add a book</button>
    </div>
  );
}
`,
    "main.tsx": `import { createRoot } from "react-dom/client";

createRoot(document.getElementById("root")!).render(<App />);
`,
  }}
/>

The console shows a message when the page first appears. Each click shows a new message, because `count` is in the list `[count]`. Lesson 13 explains effects in detail.

### `useRef`

`useRef` gives you a box called a **ref**, with one property: `current`. You can put any value in `ref.current`. Changing it does **not** update the screen.

<figure className="react-fig">
<svg viewBox="0 20 520 104" role="img" aria-labelledby="fig-h-ref" style={{ width: "100%", maxWidth: 520, height: "auto" }}>
  <title id="fig-h-ref">useRef: ref.current points to the real input element. Changing ref.current does not re-render</title>
  <rect x="10" y="30" width="150" height="50" rx="8" style={{ fill: "var(--accent-soft)", stroke: "var(--accent)", strokeWidth: 1.5 }} />
  <text x="85.0" y="52.0" textAnchor="middle" style={{ fill: "var(--accent)", fontSize: 13, fontWeight: 700, fontFamily: "var(--mono)" }}>inputRef</text>
  <text x="85.0" y="69.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>current: ●</text>
  <path d="M160 55 L300 55" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M300 55 L291.7 58.5 L291.7 51.5 Z" style={{ fill: "var(--faint)" }} />
  <text x="230.0" y="47.0" textAnchor="middle" style={{ fill: "var(--muted)", fontSize: 11, fontFamily: "var(--mono)" }}>points to</text>
  <rect x="305" y="30" width="205" height="50" rx="8" style={{ fill: "var(--ok-soft)", stroke: "var(--ok)", strokeWidth: 1.5 }} />
  <text x="407.5" y="52.0" textAnchor="middle" style={{ fill: "var(--ok)", fontSize: 13, fontWeight: 700, fontFamily: "var(--mono)" }}>&lt;input /&gt;</text>
  <text x="407.5" y="69.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>the real element on the page</text>
  <text x="260" y="115" textAnchor="middle" style={{ fill: "var(--muted)", fontSize: 12, fontFamily: "var(--sans)" }}>Changing ref.current does not update the screen.</text>
  <circle r="6" style={{ fill: "var(--accent-secondary)" }}>
    <animateMotion dur="1.8s" repeatCount="indefinite" path="M160 55 L300 55" />
  </circle>
</svg>
<figcaption>A ref is a box with one property, current. Here it holds a link to the input element.</figcaption>
</figure>

A common use is to hold a link to a real element, for example to move the cursor into an input box.

      <input ref={inputRef} placeholder="Search books" />{" "}
      <button onClick={focusSearch}>Go to search</button>
    </div>
  );
}
`,
    "main.tsx": `import { createRoot } from "react-dom/client";

createRoot(document.getElementById("root")!).render(<App />);
`,
  }}
/>

`ref={inputRef}` connects the ref to the input. After that, `inputRef.current` is the real input element. `?.` means: call `focus()` only if the element is there.

### `useContext`

`useContext` reads a value that a parent shares with all components below it. You do not need to pass the value as a prop through every level.

<figure className="react-fig">
<svg viewBox="0 0 520 190" role="img" aria-labelledby="fig-h-context" style={{ width: "100%", maxWidth: 520, height: "auto" }}>
  <title id="fig-h-context">useContext: the Provider shares the theme. ThemedBadge reads it directly, Toolbar in the middle passes nothing</title>
  <rect x="160" y="10" width="200" height="44" rx="8" style={{ fill: "var(--info-soft)", stroke: "var(--info)", strokeWidth: 1.5 }} />
  <text x="260.0" y="29.0" textAnchor="middle" style={{ fill: "var(--info)", fontSize: 13, fontWeight: 700, fontFamily: "var(--mono)" }}>Provider value="dark"</text>
  <text x="260.0" y="46.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>shares the theme</text>
  <path d="M260 54 L260 76" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none", strokeDasharray: "5 4" }} />
  <path d="M260 76 L256.5 67.7 L263.5 67.7 Z" style={{ fill: "var(--faint)" }} />
  <rect x="185" y="78" width="150" height="36" rx="8" style={{ fill: "var(--panel2)", stroke: "var(--faint)", strokeWidth: 1.5 }} />
  <text x="260.0" y="93.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Toolbar</text>
  <text x="260.0" y="110.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>passes nothing</text>
  <path d="M260 114 L260 136" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none", strokeDasharray: "5 4" }} />
  <path d="M260 136 L256.5 127.7 L263.5 127.7 Z" style={{ fill: "var(--faint)" }} />
  <rect x="170" y="138" width="180" height="44" rx="8" style={{ fill: "var(--ok-soft)", stroke: "var(--ok)", strokeWidth: 1.5 }} />
  <text x="260.0" y="157.0" textAnchor="middle" style={{ fill: "var(--ok)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>ThemedBadge</text>
  <text x="260.0" y="174.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>useContext → "dark"</text>
  <path d="M360 32 Q470 100 352 160" style={{ fill: "none", stroke: "var(--info)", strokeWidth: 2 }} />
  <circle r="6" style={{ fill: "var(--info)" }}>
    <animateMotion dur="2s" repeatCount="indefinite" path="M360 32 Q470 100 352 160" />
  </circle>
</svg>
<figcaption>The value goes straight from the Provider to the component that reads it. The middle component is skipped.</figcaption>
</figure>

      <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
        Switch theme
      </button>
  );
}
`,
    "Toolbar.tsx": `import ThemedBadge from "./ThemedBadge";

// Toolbar does not know about the theme. It just shows the badge.
  return <div><ThemedBadge /></div>;
}
`,
    "ThemedBadge.tsx": `import { useContext } from "react";

  const theme = useContext(ThemeContext);
  return <p className={"badge " + theme}>Book Corner: {theme} theme</p>;
}
`,
    "App.css": `.badge { display: inline-block; padding: 8px 14px; border-radius: 8px; }
.light { background: #f1f5f9; color: #0f172a; }
.dark { background: #0f172a; color: #f8fafc; }
`,
    "main.tsx": `import { createRoot } from "react-dom/client";

createRoot(document.getElementById("root")!).render(<App />);
`,
  }}
/>

`App` shares `theme` with `<ThemeContext.Provider value={theme}>`. `ThemedBadge` reads it with `useContext(ThemeContext)`. `Toolbar`, in the middle, does not pass any props.

### `useReducer`

`useReducer` is like `useState`, but for state with many different changes. You write all the changes in one function, called a **reducer**. Then you call `dispatch` with an **action** that names the change.

<figure className="react-fig">
<svg viewBox="0 30 520 64" role="img" aria-labelledby="fig-h-reducer" style={{ width: "100%", maxWidth: 520, height: "auto" }}>
  <title id="fig-h-reducer">useReducer: a button dispatches an action, the reducer works out the new count, the screen updates</title>
  <rect x="5" y="40" width="120" height="44" rx="8" style={{ fill: "var(--accent-soft)", stroke: "var(--accent)", strokeWidth: 1.5 }} />
  <text x="65.0" y="59.0" textAnchor="middle" style={{ fill: "var(--accent)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>dispatch</text>
  <text x="65.0" y="76.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>&#123; type: "add" &#125;</text>
  <path d="M125 62 L160 62" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M160 62 L151.7 65.5 L151.7 58.5 Z" style={{ fill: "var(--faint)" }} />
  <rect x="165" y="40" width="190" height="44" rx="8" style={{ fill: "var(--accent-secondary-soft)", stroke: "var(--accent-secondary)", strokeWidth: 1.5 }} />
  <text x="260.0" y="59.0" textAnchor="middle" style={{ fill: "var(--accent-secondary)", fontSize: 13, fontWeight: 700, fontFamily: "var(--mono)" }}>cartReducer</text>
  <text x="260.0" y="76.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>(count, action) → new count</text>
  <path d="M355 62 L390 62" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M390 62 L381.7 65.5 L381.7 58.5 Z" style={{ fill: "var(--faint)" }} />
  <rect x="395" y="40" width="120" height="44" rx="8" style={{ fill: "var(--ok-soft)", stroke: "var(--ok)", strokeWidth: 1.5 }} />
  <text x="455.0" y="59.0" textAnchor="middle" style={{ fill: "var(--ok)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>count = 1</text>
  <text x="455.0" y="76.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>screen updates</text>
  <circle r="6" style={{ fill: "var(--accent-secondary)" }}>
    <animateMotion dur="2.4s" repeatCount="indefinite" path="M125 62 L160 62 M355 62 L390 62" />
  </circle>
</svg>
<figcaption>Buttons only name the change. The reducer decides the new value.</figcaption>
</figure>

      <p>Books in cart: {count}</p>
      <button onClick={() => dispatch({ type: "add" })}>Add</button>{" "}
      <button onClick={() => dispatch({ type: "remove" })}>Remove</button>{" "}
      <button onClick={() => dispatch({ type: "clear" })}>Clear</button>
    </div>
  );
}
`,
    "main.tsx": `import { createRoot } from "react-dom/client";

createRoot(document.getElementById("root")!).render(<App />);
`,
  }}
/>

Look at this line:

```tsx
const [count, dispatch] = useReducer(cartReducer, 0);
```

- `cartReducer` is the function that decides each change.
- `0` is the starting value.
- `dispatch({ type: "add" })` asks the reducer to do the "add" change.

All the cart rules live in one place: `cartReducer`.

### `useMemo`

`useMemo` remembers the **result** of a calculation. It does the calculation again only when its inputs change. This saves time when the calculation is slow.

<figure className="react-fig">
<svg viewBox="0 0 520 170" role="img" aria-labelledby="fig-h-memo" style={{ width: "100%", maxWidth: 520, height: "auto" }}>
  <title id="fig-h-memo">useMemo: if search changed, calculate again. If not, reuse the saved result</title>
  <rect x="10" y="63" width="130" height="44" rx="8" style={{ fill: "var(--accent-soft)", stroke: "var(--accent)", strokeWidth: 1.5 }} />
  <text x="75.0" y="82.0" textAnchor="middle" style={{ fill: "var(--accent)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Render</text>
  <text x="75.0" y="99.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>is search new?</text>
  <path d="M140 75 L250 32" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M250 32 L243.6 38.3 L241.0 31.8 Z" style={{ fill: "var(--faint)" }} />
  <text x="195.0" y="50" textAnchor="middle" style={{ fill: "var(--muted)", fontSize: 11, fontFamily: "var(--mono)" }}>yes</text>
  <rect x="255" y="10" width="255" height="44" rx="8" style={{ fill: "var(--accent-secondary-soft)", stroke: "var(--accent-secondary)", strokeWidth: 1.5 }} />
  <text x="382.5" y="29.0" textAnchor="middle" style={{ fill: "var(--accent-secondary)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Filter the books again</text>
  <text x="382.5" y="46.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>slow work, then save the result</text>
  <path d="M140 95 L250 138" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M250 138 L241.0 138.2 L243.6 131.7 Z" style={{ fill: "var(--faint)" }} />
  <text x="195.0" y="128" textAnchor="middle" style={{ fill: "var(--muted)", fontSize: 11, fontFamily: "var(--mono)" }}>no</text>
  <rect x="255" y="116" width="255" height="44" rx="8" style={{ fill: "var(--ok-soft)", stroke: "var(--ok)", strokeWidth: 1.5 }} />
  <text x="382.5" y="135.0" textAnchor="middle" style={{ fill: "var(--ok)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Reuse the saved result</text>
  <text x="382.5" y="152.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>no slow work</text>
  <circle r="6" style={{ fill: "var(--ok)" }}>
    <animateMotion dur="1.6s" repeatCount="indefinite" path="M140 95 L250 138" />
  </circle>
</svg>
<figcaption>useMemo does the slow work only when its inputs change.</figcaption>
</figure>

      <input placeholder="Search" value={search} onChange={(e) => setSearch(e.target.value)} />{" "}
      <button onClick={() => setLikes(likes + 1)}>Like the shop ({likes})</button>
      <ul>
        {results.map((b) => <li key={b}>{b}</li>)}
      </ul>
    </div>
  );
}
`,
    "main.tsx": `import { createRoot } from "react-dom/client";

createRoot(document.getElementById("root")!).render(<App />);
`,
  }}
/>

Type in the box. The console shows "Filtering..." each time. Now click **Like the shop**. The page updates, but the console shows nothing new. `useMemo` reused the old result, because `search` did not change.

### `useCallback`

`useCallback` remembers a **function**, so the same function is used on every render. This matters when you pass the function to a child that only re-renders when its props change.

<figure className="react-fig">
<svg viewBox="0 0 520 140" role="img" aria-labelledby="fig-h-callback" style={{ width: "100%", maxWidth: 520, height: "auto" }}>
  <title id="fig-h-callback">useCallback: render 1 and render 2 both use the same handleBuy function</title>
  <rect x="10" y="10" width="140" height="40" rx="8" style={{ fill: "var(--accent-soft)", stroke: "var(--accent)", strokeWidth: 1.5 }} />
  <text x="80.0" y="35.0" textAnchor="middle" style={{ fill: "var(--accent)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Render 1</text>
  <rect x="10" y="90" width="140" height="40" rx="8" style={{ fill: "var(--accent-soft)", stroke: "var(--accent)", strokeWidth: 1.5 }} />
  <text x="80.0" y="115.0" textAnchor="middle" style={{ fill: "var(--accent)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Render 2</text>
  <path d="M150 30 L330 62" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M330 62 L321.2 64.0 L322.5 57.1 Z" style={{ fill: "var(--faint)" }} />
  <path d="M150 110 L330 78" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M330 78 L322.5 82.9 L321.2 76.0 Z" style={{ fill: "var(--faint)" }} />
  <rect x="335" y="45" width="175" height="50" rx="8" style={{ fill: "var(--ok-soft)", stroke: "var(--ok)", strokeWidth: 1.5 }} />
  <text x="422.5" y="67.0" textAnchor="middle" style={{ fill: "var(--ok)", fontSize: 13, fontWeight: 700, fontFamily: "var(--mono)" }}>handleBuy</text>
  <text x="422.5" y="84.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>the same function</text>
  <circle r="6" style={{ fill: "var(--accent-secondary)" }}>
    <animateMotion dur="2.4s" repeatCount="indefinite" path="M150 30 L330 62 M150 110 L330 78" />
  </circle>
</svg>
<figcaption>With useCallback, every render gets the same function, not a new one.</figcaption>
</figure>

```tsx
const handleBuy = useCallback((title: string) => {
  console.log("Buying " + title);
}, []); // the same function every render
```

Without `useCallback`, a new `handleBuy` function is made on every render. You will use it in the performance lesson. For now, remember: `useMemo` remembers a **value**, `useCallback` remembers a **function**.

## Choosing the Appropriate Hook

When you are not sure which hook to use, ask these questions in order:

1. **Does the screen need to change when this value changes?** Use `useState`. If there are many kinds of changes, use `useReducer`.
2. **Do you need to do something outside React**, such as load data or start a timer? Use `useEffect`.
3. **Do you need to remember something without updating the screen**, or reach a real element? Use `useRef`.
4. **Do many components at different levels need the same data?** Use `useContext`.
5. **Is the app slow because of a big calculation or many re-renders?** Then try `useMemo` or `useCallback`.

Start with `useState`. Add the other hooks only when you have the problem they solve. Do not add `useMemo` and `useCallback` everywhere "just in case".

## Common mistakes

<div className="tscroll">

| Mistake | What you see | Fix |
|---|---|---|
| Calling a hook inside an `if` or loop | Error: `Rendered more hooks than during the previous render` | Call every hook at the top of the component |
| Calling a hook in a normal function | Error: `Invalid hook call` | Call hooks only in components or custom hooks |
| Using `useRef` for data the screen shows | The screen does not update | Use `useState` for values the screen shows |
| Forgetting the dependency array in `useEffect` | The effect runs after every render | Add `[ ]` with the values to watch |
| Reading `useContext` without a Provider | You always get the default value | Wrap the components in `<MyContext.Provider value={...}>` |
| Adding `useMemo` to every small value | Code is harder to read, and not faster | Use it only for slow calculations |

</div>

## Check Yourself

## Exercises

## What to Remember

- Hooks are functions starting with `use`. Call them only at the top of components or custom hooks.
- State hooks remember data, effect hooks run code after rendering, refs remember without re-rendering, context shares data, and performance hooks skip work.
- Start with `useState`. Reach for other hooks only when you have the problem they solve.

Next: Custom Hooks
