# Cheat Sheet

Course: [React](https://www.devtutorials.ai/learn/react) · Section: Reference
Source: https://www.devtutorials.ai/learn/react/reference/cheat-sheet

> A quick reference for the whole course: TSX, components, props and state, events, forms, hooks, context, state management, routing, authentication, API integration and performance.

## How to Use This Cheat Sheet

This page is a quick reference for everything in the course. Each section shows the most common patterns as short, ready-to-copy code.

Use it when you know **what** you want to do but forget the exact code. Each section names the lesson where the topic is explained in full.

### Real-World Example

A developer is building a bookshop page and needs the exact syntax for a controlled input or a `useEffect` cleanup. Instead of reading a full lesson again, they look it up here in a few seconds and copy the pattern.

## TSX

TSX is HTML-like syntax inside TypeScript (Lesson 2).

```tsx
const name = "Book Corner";
const element = (
  <>                                       {/* Fragment: no extra tag */}
    <h1 className="title">{name}</h1>       {/* {} runs JavaScript */}
    <img src="logo.png" alt="Logo" />       {/* close every tag */}
    <p style={{ color: "green" }}>Open</p> {/* style is an object */}
  </>
);
```

| HTML | TSX |
|---|---|
| `class="x"` | `className="x"` |
| `for="email"` | `htmlFor="email"` |
| `onclick="..."` | `onClick={handleClick}` |
| `<br>` | `<br />` |

## Components

A component is a function that returns TSX. Its name starts with a capital letter (Lesson 3).

```tsx
// BookCard.tsx
export default function BookCard() {
  return <div className="card">The Alchemist</div>;
}

// App.tsx
import BookCard from "./BookCard";

export default function App() {
  return (
    <main>
      <BookCard />
      <BookCard />
    </main>
  );
}
```

## Props & State

**Props** are inputs from the parent (read-only). **State** is data a component owns and can change (Lessons 4–5).

```tsx
interface BookProps {
  title: string;
  price?: number;            // ? = optional
  children?: ReactNode;      // content between the tags
}

function Book({ title, price = 0 }: BookProps) {   // default value
  return <p>{title}: ₹{price}</p>;
}

const [count, setCount] = useState(0);                 // number
const [books, setBooks] = useState<string[]>([]);      // typed array
const [user, setUser] = useState<User | null>(null);   // maybe empty

setCount(count + 1);                    // new value
setCount((c) => c + 1);                 // from the previous value
setBooks([...books, "Ikigai"]);         // add (new array)
setBooks(books.filter((b) => b !== "Ikigai")); // remove
setUser({ ...user!, name: "Asha" });    // update one field
```

<figure className="react-fig">
<svg viewBox="0 0 520 170" role="img" aria-labelledby="fig-x-flow" style={{ width: "100%", maxWidth: 520, height: "auto" }}>
  <title id="fig-x-flow">Data moves down as props, events move up as callbacks, and context reaches any depth</title>
  <rect x="185" y="10" width="150" height="44" rx="8" style={{ fill: "var(--accent-soft)", stroke: "var(--accent)", strokeWidth: 1.5 }} />
  <text x="260.0" y="29.0" textAnchor="middle" style={{ fill: "var(--accent)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Parent</text>
  <text x="260.0" y="46.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>owns the state</text>
  <rect x="60" y="110" width="150" height="44" rx="8" style={{ fill: "var(--panel2)", stroke: "var(--faint)", strokeWidth: 1.5 }} />
  <text x="135.0" y="129.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Child</text>
  <text x="135.0" y="146.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>shows props</text>
  <rect x="310" y="110" width="150" height="44" rx="8" style={{ fill: "var(--info-soft)", stroke: "var(--info)", strokeWidth: 1.5 }} />
  <text x="385.0" y="129.0" textAnchor="middle" style={{ fill: "var(--info)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Deep child</text>
  <text x="385.0" y="146.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 11, fontFamily: "var(--sans)" }}>useContext</text>
  <path d="M195 54 L95 106" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M95 106 L100.7 99.1 L104.0 105.3 Z" style={{ fill: "var(--faint)" }} />
  <text x="118" y="74" textAnchor="middle" style={{ fill: "var(--accent)", fontSize: 11, fontWeight: 700, fontFamily: "var(--sans)" }}>props</text>
  <path d="M180 106 L280 54" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M280 54 L274.3 60.9 L271.0 54.7 Z" style={{ fill: "var(--faint)" }} />
  <text x="262" y="92" textAnchor="middle" style={{ fill: "var(--ok)", fontSize: 11, fontWeight: 700, fontFamily: "var(--mono)" }}>onChange()</text>
  <path d="M335 32 Q470 40 400 106" style={{ fill: "none", stroke: "var(--info)", strokeWidth: 2, strokeDasharray: "5 4" }} />
  <text x="470" y="70" textAnchor="middle" style={{ fill: "var(--info)", fontSize: 11, fontWeight: 700, fontFamily: "var(--sans)" }}>context</text>
  <circle r="6" style={{ fill: "var(--accent)" }}>
    <animateMotion dur="2s" repeatCount="indefinite" path="M195 54 L95 106" />
  </circle>
  <circle r="6" style={{ fill: "var(--ok)" }}>
    <animateMotion dur="2s" repeatCount="indefinite" path="M180 106 L280 54" />
  </circle>
  <circle r="6" style={{ fill: "var(--info)" }}>
    <animateMotion dur="2.4s" repeatCount="indefinite" path="M335 32 Q470 40 400 106" />
  </circle>
</svg>
<figcaption>Props down, events up, context across.</figcaption>
</figure>

      {title}: ₹{price} <button onClick={() => onBuy(title)}>Buy</button>
    </li>
  );
}

const books = [
  { id: 1, title: "The Alchemist", price: 299 },
  { id: 2, title: "Wings of Fire", price: 350 },
];

  const [cart, setCart] = useState<string[]>([]);

  return (
    <div>
      <ul>
        {books.map((b) => (
          <Book key={b.id} title={b.title} price={b.price} onBuy={(t) => setCart([...cart, t])} />
        ))}
      </ul>
      <p>Cart: {cart.length === 0 ? "empty" : cart.join(", ")}</p>
    </div>
  );
}
`,
    "main.tsx": `import { createRoot } from "react-dom/client";

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

## Event Handling Patterns

Pass a function, do not call it (Lesson 6).

```tsx
<button onClick={handleClick}>Save</button>              // pass the function
<button onClick={() => remove(book.id)}>Delete</button>  // with an argument

function handleChange(e: ChangeEvent<HTMLInputElement>) {
  setName(e.target.value);
}

function handleKey(e: KeyboardEvent<HTMLInputElement>) {
  if (e.key === "Enter") search();
}

function handleSubmit(e: FormEvent) {
  e.preventDefault();          // stop the page reload
}

<div onClick={() => open()}>
  <button onClick={(e) => { e.stopPropagation(); like(); }}>Like</button>
</div>
```

Conditional rendering and lists (Lessons 7–8):

```tsx
{isLoading && <p>Loading...</p>}
{error ? <p className="error">{error}</p> : <BookList />}
{books.map((b) => <li key={b.id}>{b.title}</li>)}   // key = stable id
```

## Forms & Validation Templates

A controlled form keeps every value in state (Lessons 9–10).

```tsx
interface FormValues { email: string; password: string; }
type FormErrors = Partial<Record<keyof FormValues, string>>;

function validate(v: FormValues): FormErrors {
  const errors: FormErrors = {};
  if (!v.email.includes("@")) errors.email = "Enter a valid email.";
  if (v.password.length < 8) errors.password = "Use at least 8 characters.";
  return errors;
}

const [values, setValues] = useState<FormValues>({ email: "", password: "" });
const [errors, setErrors] = useState<FormErrors>({});

function handleChange(e: ChangeEvent<HTMLInputElement>) {
  setValues({ ...values, [e.target.name]: e.target.value });   // one handler
}

function handleSubmit(e: FormEvent) {
  e.preventDefault();
  const found = validate(values);
  setErrors(found);
  if (Object.keys(found).length === 0) save(values);
}
```

      <input name="email" value={values.email} onChange={handleChange} placeholder="Email" />
      {errors.email && <small style={{ color: "crimson" }}>{errors.email}</small>}
      <input name="password" type="password" value={values.password} onChange={handleChange} placeholder="Password" />
      {errors.password && <small style={{ color: "crimson" }}>{errors.password}</small>}
      <button type="submit">Sign up</button>
      {done && <p>Welcome!</p>}
    </form>
  );
}
`,
    "main.tsx": `import { createRoot } from "react-dom/client";

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

## React Hooks

Hooks are called at the top of a component, never inside `if` or loops (Lessons 11–13).

```tsx
const [value, setValue] = useState(0);

const [state, dispatch] = useReducer(reducer, initialState);

useEffect(() => {
  const id = setInterval(tick, 1000);   // runs after render
  return () => clearInterval(id);       // cleanup
}, []);                                 // [] = once; [x] = when x changes

const inputRef = useRef<HTMLInputElement>(null);
inputRef.current?.focus();

const total = useMemo(() => sum(items), [items]);
const handleSave = useCallback(() => save(id), [id]);

const theme = useContext(ThemeContext);

// a custom hook: a function starting with "use" that calls hooks
function useToggle(start = false) {
  const [on, setOn] = useState(start);
  return [on, () => setOn(!on)] as const;
}
```

<figure className="react-fig">
<svg viewBox="0 0 520 200" role="img" aria-labelledby="fig-x-hooks" style={{ width: "100%", maxWidth: 520, height: "auto" }}>
  <title id="fig-x-hooks">Which hook should I use? A quick guide</title>
  <rect x="10" y="10" width="230" height="32" rx="8" style={{ fill: "var(--panel2)", stroke: "var(--faint)", strokeWidth: 1.5 }} />
  <text x="125.0" y="31.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>A value that changes the screen?</text>
  <path d="M240 26 L280 26" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M280 26 L271.7 29.5 L271.7 22.5 Z" style={{ fill: "var(--faint)" }} />
  <rect x="285" y="10" width="225" height="32" rx="8" style={{ fill: "var(--accent-soft)", stroke: "var(--accent)", strokeWidth: 1.5 }} />
  <text x="397.5" y="31.0" textAnchor="middle" style={{ fill: "var(--accent)", fontSize: 13, fontWeight: 700, fontFamily: "var(--mono)" }}>useState</text>
  <rect x="10" y="48" width="230" height="32" rx="8" style={{ fill: "var(--panel2)", stroke: "var(--faint)", strokeWidth: 1.5 }} />
  <text x="125.0" y="69.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Many related updates?</text>
  <path d="M240 64 L280 64" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M280 64 L271.7 67.5 L271.7 60.5 Z" style={{ fill: "var(--faint)" }} />
  <rect x="285" y="48" width="225" height="32" rx="8" style={{ fill: "var(--accent-soft)", stroke: "var(--accent)", strokeWidth: 1.5 }} />
  <text x="397.5" y="69.0" textAnchor="middle" style={{ fill: "var(--accent)", fontSize: 13, fontWeight: 700, fontFamily: "var(--mono)" }}>useReducer</text>
  <rect x="10" y="86" width="230" height="32" rx="8" style={{ fill: "var(--panel2)", stroke: "var(--faint)", strokeWidth: 1.5 }} />
  <text x="125.0" y="107.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Run code after render / fetch?</text>
  <path d="M240 102 L280 102" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M280 102 L271.7 105.5 L271.7 98.5 Z" style={{ fill: "var(--faint)" }} />
  <rect x="285" y="86" width="225" height="32" rx="8" style={{ fill: "var(--accent-secondary-soft)", stroke: "var(--accent-secondary)", strokeWidth: 1.5 }} />
  <text x="397.5" y="107.0" textAnchor="middle" style={{ fill: "var(--accent-secondary)", fontSize: 13, fontWeight: 700, fontFamily: "var(--mono)" }}>useEffect</text>
  <rect x="10" y="124" width="230" height="32" rx="8" style={{ fill: "var(--panel2)", stroke: "var(--faint)", strokeWidth: 1.5 }} />
  <text x="125.0" y="145.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Keep a value without re-render?</text>
  <path d="M240 140 L280 140" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M280 140 L271.7 143.5 L271.7 136.5 Z" style={{ fill: "var(--faint)" }} />
  <rect x="285" y="124" width="225" height="32" rx="8" style={{ fill: "var(--info-soft)", stroke: "var(--info)", strokeWidth: 1.5 }} />
  <text x="397.5" y="145.0" textAnchor="middle" style={{ fill: "var(--info)", fontSize: 13, fontWeight: 700, fontFamily: "var(--mono)" }}>useRef</text>
  <rect x="10" y="162" width="230" height="32" rx="8" style={{ fill: "var(--panel2)", stroke: "var(--faint)", strokeWidth: 1.5 }} />
  <text x="125.0" y="183.0" textAnchor="middle" style={{ fill: "var(--ink2)", fontSize: 13, fontWeight: 700, fontFamily: "var(--sans)" }}>Share data with many parts?</text>
  <path d="M240 178 L280 178" style={{ stroke: "var(--faint)", strokeWidth: 2, fill: "none" }} />
  <path d="M280 178 L271.7 181.5 L271.7 174.5 Z" style={{ fill: "var(--faint)" }} />
  <rect x="285" y="162" width="225" height="32" rx="8" style={{ fill: "var(--ok-soft)", stroke: "var(--ok)", strokeWidth: 1.5 }} />
  <text x="397.5" y="183.0" textAnchor="middle" style={{ fill: "var(--ok)", fontSize: 13, fontWeight: 700, fontFamily: "var(--mono)" }}>useContext</text>
</svg>
<figcaption>Start with useState. Reach for the others when you need what they do.</figcaption>
</figure>

Two rules of hooks: call them only at the top level of a component (not in `if`, loops or nested functions), and only from components or custom hooks whose names start with `use`.

      <p>Seconds: {seconds}</p>
      <button onClick={toggleRunning}>{running ? "Pause" : "Start"}</button>{" "}
      <input ref={inputRef} placeholder="Note" />{" "}
      <button onClick={() => inputRef.current?.focus()}>Focus the box</button>
    </div>
  );
}
`,
    "main.tsx": `import { createRoot } from "react-dom/client";

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

## Context API

Context shares a value with every component inside its provider (Lesson 15).

```tsx
interface ThemeValue { theme: "light" | "dark"; toggle: () => void; }
const ThemeContext = createContext<ThemeValue | null>(null);

export function ThemeProvider({ children }: { children: ReactNode }) {
  const [theme, setTheme] = useState<"light" | "dark">("light");
  const toggle = () => setTheme(theme === "light" ? "dark" : "light");
  return <ThemeContext.Provider value={{ theme, toggle }}>{children}</ThemeContext.Provider>;
}

export function useTheme() {
  const ctx = useContext(ThemeContext);
  if (!ctx) throw new Error("useTheme must be used inside ThemeProvider");
  return ctx;
}

// anywhere inside the provider
const { theme, toggle } = useTheme();
```

## State Management

Where should state live? (Lesson 14)

| The data is used by... | Put the state in... |
|---|---|
| one component | `useState` in that component |
| a parent and its children | the parent, passed down as props |
| many parts of the app | a context (with `useReducer` if updates are complex) |
| the server | fetch it, and keep a copy in state |

```tsx
type Action =
  | { type: "added"; item: Item }
  | { type: "removed"; id: number };

function cartReducer(items: Item[], action: Action): Item[] {
  switch (action.type) {
    case "added":   return [...items, action.item];
    case "removed": return items.filter((i) => i.id !== action.id);
  }
}

const [items, dispatch] = useReducer(cartReducer, []);
dispatch({ type: "added", item: book });
```

      <button onClick={() => dispatch({ type: "added", title: "Atomic Habits" })}>Add Atomic Habits</button>{" "}
      <button onClick={() => dispatch({ type: "cleared" })}>Clear</button>
    </div>
  );
}

  return (
  );
}
`,
    "main.tsx": `import { createRoot } from "react-dom/client";

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

## Routing

React Router shows a page for each URL (Lesson 16).

```tsx
import { BrowserRouter, Routes, Route, Link, NavLink, useParams, useNavigate } from "react-router-dom";

<BrowserRouter>
  <nav>
    <NavLink to="/" end>Home</NavLink>        {/* gets class "active" */}
    <Link to="/books">Books</Link>
  </nav>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/books" element={<BookList />} />
    <Route path="/books/:id" element={<BookDetail />} />
    <Route path="*" element={<NotFound />} />
  </Routes>
</BrowserRouter>

const { id } = useParams();            // "/books/2" -> id is "2" (text)
const navigate = useNavigate();
navigate("/books");                    // go to a page in code
navigate(-1);                          // go back
```

## Authentication & Authorization

**Authentication** checks who you are. **Authorization** checks what you may do (Lesson 17).

```tsx
// after login, keep the JWT and the user in an auth context
const { token, user } = useAuth();

// send the token with each request
fetch(API + "/orders", { headers: { Authorization: "Bearer " + token } });

// read the payload (the middle part) of a JWT, for display only
const payload = JSON.parse(atob(token.split(".")[1]));

// protect a route
function ProtectedRoute({ children, role }: { children: ReactNode; role?: string }) {
  const { user } = useAuth();
  if (!user) return <Navigate to="/login" replace />;
  if (role && user.role !== role) return <p>You do not have access.</p>;
  return <>{children}</>;
}

<Route path="/admin" element={<ProtectedRoute role="admin"><Admin /></ProtectedRoute>} />
```

Hiding a page in React is only for the user's comfort. The server must still check the token on every request, because anyone can change code in their browser.

      <nav style={{ display: "flex", gap: 10 }}>
        <Link to="/">Home</Link>
        <Link to="/admin">Admin</Link>
        <Link to="/login">Login</Link>
      </nav>
      <p>Signed in as: {user ? user.name + " (" + user.role + ")" : "nobody"}</p>
        <Route path="/" element={<h2>Home</h2>} />
            <h2>Login</h2>
            <button onClick={() => setUser({ name: "Asha", role: "staff" })}>Login as staff</button>{" "}
            <button onClick={() => setUser({ name: "Ravi", role: "admin" })}>Login as admin</button>
          </div>
        } />
        <Route path="/admin" element={<ProtectedRoute role="admin"><h2>Admin panel</h2></ProtectedRoute>} />
  );
}
`,
    "main.tsx": `import { createRoot } from "react-dom/client";

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

## API Integration

Fetch data with loading and error states (Lesson 22).

```tsx
const [books, setBooks] = useState<Book[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");

useEffect(() => {
  async function load() {
    try {
      const response = await fetch(import.meta.env.VITE_API_URL + "/books");
      if (!response.ok) throw new Error("Status " + response.status);
      setBooks(await response.json());
    } catch {
      setError("Could not load books. Please try again.");
    } finally {
      setLoading(false);
    }
  }
  load();
}, []);

// POST, PUT and DELETE
await fetch(url, {
  method: "POST",                                   // or "PUT"
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(newBook),
});
await fetch(url + "/" + id, { method: "DELETE" });
```

Error boundaries for render crashes (Lesson 24): a class component with `static getDerivedStateFromError()` that renders a fallback.

      {books.map((b) => <li key={b.id}>{b.title}</li>)}
    </ul>
  );
}
`,
    "main.tsx": `import { createRoot } from "react-dom/client";

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

## Performance Optimization

Measure first, then optimize the slow parts (Lesson 25).

```tsx
const BookRow = memo(function BookRow({ book }: { book: Book }) { ... });   // skip same props

const cheap = useMemo(() => books.filter((b) => b.price < 300), [books]);  // keep a value
const handleSelect = useCallback((id: number) => select(id), []);          // keep a function

const Admin = lazy(() => import("./Admin"));          // code splitting
<Suspense fallback={<p>Loading...</p>}>
  <Admin />
</Suspense>
```

- Keep state close to where it is used.
- Use stable keys (ids, not indexes) in lists.
- Test speed with a production build (`npm run build`).

Easy Way to Remember: state for change, props for passing, effects for outside work, context for sharing, memo for speed.

## Common mistakes

<div className="tscroll">

| Mistake | What you see | Fix |
|---|---|---|
| Calling a handler: `onClick={save()}` | It runs on every render | Pass it: `onClick={save}` or `onClick={() => save(id)}` |
| Changing state directly: `books.push(b)` | The screen does not update | Make a new array: `setBooks([...books, b])` |
| No `key` in a list | A console warning, wrong rows update | Use `key={item.id}` |
| Hooks inside `if` or loops | Error: rendered fewer hooks than expected | Call hooks at the top of the component |
| `useEffect` without a dependency list | The effect runs after every render | Add `[]` or the values it uses |
| Not checking `response.ok` | Error pages treated as data | Throw when `!response.ok` |
| Trusting React to protect data | Anyone can call the API | Check tokens on the server too |

</div>

## Check Yourself

## What to Remember

- Keep this page open while you build. Each section points to the lesson with the full explanation.
- Props down, events up, context across. State changes go through setters, with new arrays and objects.
- Fetch with `try`/`catch` and `response.ok`, protect routes but check on the server too, and optimize only what is slow.
