React cheatsheet from first components and hooks to reusable architecture, performance, testing, and advanced patterns.
React Cheatsheet
Section titled “React Cheatsheet”React is a JavaScript library for building user interfaces from reusable components. You describe what the UI should look like for the current data, and React updates the browser when that data changes.
| Concept | Purpose |
|---|---|
| Component | Reusable UI function that returns JSX |
| Props | Inputs passed from a parent component |
| State | Data a component remembers between renders |
| Event handler | Code triggered by a user action |
| Hook | Function such as useState or useEffect that adds React behavior |
| Context | Shared value available to nested components |
function Greeting({ name }) { return <h1>Hello, {name}!</h1>;}
export default function App() { return <Greeting name="React" />;}React component names begin with an uppercase letter. HTML tags stay lowercase, such as <button> and <section>.
1. Beginner: JSX and Components
Section titled “1. Beginner: JSX and Components”JSX Basics
Section titled “JSX Basics”JSX lets JavaScript expressions appear inside markup using {}.
const user = { name: "Asha", avatarUrl: "/images/asha.png",};
export default function Profile() { return ( <section className="profile"> <img src={user.avatarUrl} alt={`${user.name}'s avatar`} /> <h2>{user.name}</h2> <p>{user.name} is learning React.</p> </section> );}| JSX Rule | Example |
|---|---|
| Return one parent element | Wrap siblings in <div> or <>...</> |
Use className for CSS classes | <div className="card" /> |
| Close every tag | <img src={url} alt="" /> |
| Put JavaScript expressions in braces | <p>{price * quantity}</p> |
| Use camelCase DOM properties | <button onClick={save}>Save</button> |
| Write inline styles as objects | <p style={{ color: "tomato" }}>Alert</p> |
Create and Nest Components
Section titled “Create and Nest Components”function Avatar({ name, imageUrl }) { return <img className="avatar" src={imageUrl} alt={name} />;}
function UserCard({ user }) { return ( <article className="card"> <Avatar name={user.name} imageUrl={user.imageUrl} /> <h3>{user.name}</h3> <p>{user.role}</p> </article> );}
export default function App() { const user = { name: "Maya", role: "Frontend Developer", imageUrl: "/images/maya.png", };
return <UserCard user={user} />;}Fragments
Section titled “Fragments”Use a fragment when elements need grouping without adding an extra DOM node:
function Name() { return ( <> <dt>React</dt> <dd>UI library</dd> </> );}2. Props: Pass Data Down
Section titled “2. Props: Pass Data Down”Props are read-only inputs. A child component must not modify the props it receives.
function Badge({ label, variant = "default" }) { return <span className={`badge badge-${variant}`}>{label}</span>;}
export default function App() { return ( <div> <Badge label="New" variant="success" /> <Badge label="Draft" /> </div> );}Common Prop Patterns
Section titled “Common Prop Patterns”function Button({ children, onClick, disabled = false }) { return ( <button type="button" onClick={onClick} disabled={disabled}> {children} </button> );}
function Alert({ title, message }) { return ( <div role="alert"> <strong>{title}</strong> <p>{message}</p> </div> );}| Pattern | Meaning |
|---|---|
children | Content nested inside a component |
onSomething | Callback prop supplied by a parent |
| Default value | Fallback when a prop is omitted |
| Object prop | Related data passed together, such as user |
3. Conditional Rendering
Section titled “3. Conditional Rendering”React uses ordinary JavaScript conditions.
function LoginStatus({ user }) { if (!user) { return <button>Log in</button>; }
return <p>Welcome back, {user.name}.</p>;}function Inbox({ unreadCount, messages }) { return ( <section> {unreadCount > 0 && <p>You have {unreadCount} unread messages.</p>}
{messages.length === 0 ? ( <p>No messages yet.</p> ) : ( <p>Choose a message to read.</p> )} </section> );}| Need | Use |
|---|---|
| Exit early for a whole view | if (...) return ... |
| Show one of two elements | condition ? a : b |
| Show an element only when true | condition && element |
Be careful with count && <p>...</p> when count may be 0; React can render the 0. Prefer count > 0 && ....
4. Rendering Lists and Keys
Section titled “4. Rendering Lists and Keys”Use map() to turn data into components. Every item created in a list needs a stable key.
function TodoList({ todos }) { return ( <ul> {todos.map((todo) => ( <li key={todo.id}> {todo.completed ? "Done: " : "Todo: "} {todo.title} </li> ))} </ul> );}| Good Key | Risky Key |
|---|---|
Database ID: todo.id | Array index when items can move |
Stable slug: post.slug | Math.random() |
| Persistent generated ID | Values that change every render |
Keys tell React which item is which across insertions, removals, and reordering. Keys are not passed into the child as a normal prop:
<TodoItem key={todo.id} id={todo.id} todo={todo} />5. Events and State with useState
Section titled “5. Events and State with useState”State stores information that affects rendering. Updating state asks React to render again.
import { useState } from "react";
export default function Counter() { const [count, setCount] = useState(0);
function increment() { setCount(count + 1); }
return ( <div> <p>Count: {count}</p> <button type="button" onClick={increment}> Add one </button> </div> );}Event Handler Reference
Section titled “Event Handler Reference”| Event | Example |
|---|---|
| Click | <button onClick={handleClick}>Save</button> |
| Input change | <input onChange={handleChange} /> |
| Form submission | <form onSubmit={handleSubmit}> |
| Keyboard input | <input onKeyDown={handleKeyDown} /> |
| Focus / blur | <input onFocus={open} onBlur={close} /> |
Pass a function, not the result of calling one:
<button onClick={handleSave}>Save</button> // Correct<button onClick={() => deleteItem(item.id)}>Delete</button>Updating from Previous State
Section titled “Updating from Previous State”When the next value depends on the previous one, use the updater form:
function incrementThreeTimes() { setCount((current) => current + 1); setCount((current) => current + 1); setCount((current) => current + 1);}Do Not Mutate State
Section titled “Do Not Mutate State”const [user, setUser] = useState({ name: "Sam", role: "Student" });
function promoteUser() { setUser((current) => ({ ...current, role: "Mentor", }));}const [todos, setTodos] = useState([]);
function addTodo(todo) { setTodos((current) => [...current, todo]);}
function removeTodo(id) { setTodos((current) => current.filter((todo) => todo.id !== id));}| Avoid Mutation | Use Instead |
|---|---|
array.push(item) | [...array, item] |
array.splice(index, 1) | array.filter(...) |
object.name = "New" | { ...object, name: "New" } |
array.sort() on state | [...array].sort() |
6. Forms and Controlled Inputs
Section titled “6. Forms and Controlled Inputs”A controlled input gets its value from state and reports edits through an event handler.
import { useState } from "react";
export default function SignupForm() { const [form, setForm] = useState({ name: "", email: "", });
function handleChange(event) { const { name, value } = event.target; setForm((current) => ({ ...current, [name]: value, })); }
function handleSubmit(event) { event.preventDefault(); console.log("Submitted:", form); }
return ( <form onSubmit={handleSubmit}> <label> Name <input name="name" value={form.name} onChange={handleChange} /> </label>
<label> Email <input type="email" name="email" value={form.email} onChange={handleChange} /> </label>
<button type="submit">Create account</button> </form> );}Form Input Patterns
Section titled “Form Input Patterns”// Checkbox<input type="checkbox" checked={accepted} onChange={(event) => setAccepted(event.target.checked)}/>
// Select<select value={country} onChange={(event) => setCountry(event.target.value)}> <option value="in">India</option> <option value="us">United States</option></select>
// Textarea<textarea value={notes} onChange={(event) => setNotes(event.target.value)} />Use semantic labels and native validation attributes such as required, type="email", and minLength before building complex custom validation.
7. Sharing State Between Components
Section titled “7. Sharing State Between Components”When two components must stay in sync, move their state to the nearest common parent and pass values and callbacks as props.
import { useState } from "react";
function SearchBox({ query, onQueryChange }) { return ( <input value={query} onChange={(event) => onQueryChange(event.target.value)} placeholder="Search products" /> );}
function ProductList({ products, query }) { const filtered = products.filter((product) => product.name.toLowerCase().includes(query.toLowerCase()), );
return ( <ul> {filtered.map((product) => ( <li key={product.id}>{product.name}</li> ))} </ul> );}
export default function ProductsPage({ products }) { const [query, setQuery] = useState("");
return ( <> <SearchBox query={query} onQueryChange={setQuery} /> <ProductList products={products} query={query} /> </> );}Do not put derived values such as filtered into state unless there is a specific reason. Derive them from current props and state during rendering.
8. Effects with useEffect
Section titled “8. Effects with useEffect”Effects synchronize a component with something outside React: network requests, browser APIs, subscriptions, timers, or third-party widgets.
import { useEffect, useState } from "react";
export default function Clock() { const [time, setTime] = useState(() => new Date());
useEffect(() => { const intervalId = window.setInterval(() => { setTime(new Date()); }, 1000);
return () => { window.clearInterval(intervalId); }; }, []);
return <time>{time.toLocaleTimeString()}</time>;}Dependency Array Meaning
Section titled “Dependency Array Meaning”| Code | When the Effect Runs |
|---|---|
useEffect(fn) | After every render |
useEffect(fn, []) | After mounting; cleanup on unmount |
useEffect(fn, [roomId]) | After mounting and when roomId changes |
Fetch Data with Cleanup
Section titled “Fetch Data with Cleanup”import { useEffect, useState } from "react";
function UserProfile({ userId }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null);
useEffect(() => { const controller = new AbortController();
async function loadUser() { setLoading(true); setError(null);
try { const response = await fetch(`/api/users/${userId}`, { signal: controller.signal, });
if (!response.ok) { throw new Error("Unable to load user"); }
setUser(await response.json()); } catch (caughtError) { if (caughtError.name !== "AbortError") { setError(caughtError.message); } } finally { if (!controller.signal.aborted) { setLoading(false); } } }
loadUser(); return () => controller.abort(); }, [userId]);
if (loading) return <p>Loading...</p>; if (error) return <p role="alert">{error}</p>; return <h2>{user.name}</h2>;}You Usually Do Not Need an Effect For
Section titled “You Usually Do Not Need an Effect For”| Task | Better Approach |
|---|---|
| Calculate a value from props/state | Calculate during render |
| Respond to a button click | Put logic in the event handler |
| Reset an entire subtree for a new item | Give it a different key |
| Expensive derived calculation | Use useMemo only after measuring need |
9. Refs with useRef
Section titled “9. Refs with useRef”A ref stores a mutable value without causing a render. It can also point at a DOM element.
Focus an Input
Section titled “Focus an Input”import { useRef } from "react";
export default function SearchForm() { const inputRef = useRef(null);
function focusSearch() { inputRef.current.focus(); }
return ( <> <input ref={inputRef} type="search" /> <button type="button" onClick={focusSearch}> Focus search </button> </> );}Store a Timer ID
Section titled “Store a Timer ID”const timeoutRef = useRef(null);
function showMessage() { window.clearTimeout(timeoutRef.current); timeoutRef.current = window.setTimeout(() => { setVisible(false); }, 2000);}| Use State When | Use Ref When |
|---|---|
| The screen must update after a value changes | The value should persist without rendering |
| Value is rendered in JSX | You need a DOM node, timer ID, or previous value |
Do not read or write ref.current during rendering to drive visible UI; use state for that.
10. Context and useContext
Section titled “10. Context and useContext”Context supplies a value to deeply nested components without passing the same prop through every layer. Good candidates include theme, authenticated user, locale, or small app-wide configuration.
import { createContext, useContext, useState } from "react";
const ThemeContext = createContext(null);
function ThemeButton() { const { theme, toggleTheme } = useContext(ThemeContext);
return ( <button type="button" onClick={toggleTheme}> Current theme: {theme} </button> );}
export default function App() { const [theme, setTheme] = useState("light");
function toggleTheme() { setTheme((current) => (current === "light" ? "dark" : "light")); }
return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> <main className={theme}> <ThemeButton /> </main> </ThemeContext.Provider> );}Context does not automatically replace all state management. Frequently changing large values can cause many context consumers to render; split contexts or choose a dedicated state tool when the application needs it.
11. Reducers with useReducer
Section titled “11. Reducers with useReducer”useReducer is useful when several state changes belong to one workflow or when updates are easier to express as actions.
import { useReducer } from "react";
function todoReducer(state, action) { switch (action.type) { case "added": return [ ...state, { id: action.id, title: action.title, completed: false }, ]; case "toggled": return state.map((todo) => todo.id === action.id ? { ...todo, completed: !todo.completed } : todo, ); case "deleted": return state.filter((todo) => todo.id !== action.id); default: throw new Error(`Unknown action: ${action.type}`); }}
export default function TodoApp() { const [todos, dispatch] = useReducer(todoReducer, []);
function addExample() { dispatch({ type: "added", id: crypto.randomUUID(), title: "Learn hooks" }); }
return ( <> <button type="button" onClick={addExample}> Add todo </button> {todos.map((todo) => ( <label key={todo.id}> <input type="checkbox" checked={todo.completed} onChange={() => dispatch({ type: "toggled", id: todo.id })} /> {todo.title} </label> ))} </> );}Prefer useState | Prefer useReducer |
|---|---|
| A few independent values | Related transitions across a complex object |
| Straightforward setters | Actions help describe user intent |
| Simple form controls | State logic benefits from isolated tests |
12. Custom Hooks
Section titled “12. Custom Hooks”Custom hooks share stateful behavior, not rendered markup. Their names begin with use.
import { useEffect, useState } from "react";
function useOnlineStatus() { const [isOnline, setIsOnline] = useState(navigator.onLine);
useEffect(() => { function updateOnlineStatus() { setIsOnline(navigator.onLine); }
window.addEventListener("online", updateOnlineStatus); window.addEventListener("offline", updateOnlineStatus);
return () => { window.removeEventListener("online", updateOnlineStatus); window.removeEventListener("offline", updateOnlineStatus); }; }, []);
return isOnline;}
function SaveButton() { const isOnline = useOnlineStatus();
return ( <button type="button" disabled={!isOnline}> {isOnline ? "Save" : "Offline"} </button> );}Rules of Hooks
Section titled “Rules of Hooks”| Rule | Reason |
|---|---|
| Call hooks at the top level | React relies on a consistent call order |
| Call hooks only from React components or custom hooks | Hook state belongs to React rendering |
| Include reactive values used by effects in dependencies | Avoid stale values and synchronization bugs |
Do not call hooks inside conditions, loops, nested functions, or ordinary utility functions.
13. Component Design Patterns
Section titled “13. Component Design Patterns”Composition with children
Section titled “Composition with children”function Card({ title, children }) { return ( <section className="card"> <h2>{title}</h2> <div>{children}</div> </section> );}
function Dashboard() { return ( <Card title="Revenue"> <p>$4,200 this month</p> <button type="button">View report</button> </Card> );}Configurable Compound Content
Section titled “Configurable Compound Content”function Dialog({ title, children, actions }) { return ( <section role="dialog" aria-labelledby="dialog-title"> <h2 id="dialog-title">{title}</h2> <div>{children}</div> <footer>{actions}</footer> </section> );}
function DeleteDialog() { return ( <Dialog title="Delete file?" actions={ <> <button type="button">Cancel</button> <button type="button">Delete</button> </> } > This action cannot be undone. </Dialog> );}Keep Components Focused
Section titled “Keep Components Focused”| Smell | Improvement |
|---|---|
| One component loads, filters, edits, and displays everything | Extract meaningful sections or hooks |
| Many boolean props that conflict | Use clear variants or separate components |
| Child needs distant sibling data | Lift shared state to their common parent |
| Copy-pasted stateful behavior | Extract a custom hook |
Favor composition over building one enormous “do everything” component.
14. Data Loading and Server State
Section titled “14. Data Loading and Server State”Small examples can fetch in an effect, but real applications often need caching, request deduplication, retries, background refreshing, routing integration, and server rendering.
| Requirement | Typical Direction |
|---|---|
| One client-only request in a small widget | useEffect with loading/error/abort handling |
| Route-level data | Use the data-loading API of the selected framework/router |
| Cached shared API data | Use a server-state library selected by the project |
| Server-rendered application | Fetch through the framework’s server/data primitives |
Always represent the main states:
function Results({ data, loading, error }) { if (loading) return <p>Loading results...</p>; if (error) return <p role="alert">Could not load results.</p>; if (data.length === 0) return <p>No matching results.</p>;
return ( <ul> {data.map((result) => ( <li key={result.id}>{result.name}</li> ))} </ul> );}Avoid storing the same server data in several unrelated components without a deliberate synchronization strategy.
15. Routing Concepts
Section titled “15. Routing Concepts”React does not include a full browser router by itself. Applications typically use a framework or routing library.
| Routing Need | Concept |
|---|---|
| Display UI for a URL | Route |
| Move without full page reload | Link/navigation component |
Read /products/:id | Route parameter |
Read ?query=react | Search parameter |
| Protect user-only pages | Authentication/authorization boundary |
| Share page layout | Nested layout route |
An application with pages might be organized as:
src/ components/ Button.jsx ProductCard.jsx pages/ HomePage.jsx ProductPage.jsx hooks/ useProducts.js App.jsxFollow the chosen framework or router for route definition, loading, error pages, and navigation rather than inventing URL state by hand.
16. Styling React Components
Section titled “16. Styling React Components”React can work with ordinary CSS or a styling system chosen by the project.
import "./Button.css";
function Button({ variant = "primary", children }) { return ( <button className={`button button-${variant}`} type="button"> {children} </button> );}.button { border: 0; border-radius: 0.5rem; padding: 0.5rem 1rem;}
.button-primary { background: #2563eb; color: white;}Conditional Classes
Section titled “Conditional Classes”function Tab({ active, children }) { const className = active ? "tab tab-active" : "tab"; return <button className={className}>{children}</button>;}| Approach | Useful For |
|---|---|
| Plain CSS | Simple sites and shared global design tokens |
| CSS Modules | Locally scoped component classes |
| Utility classes | Rapid composition with a configured design system |
| CSS-in-JS | Projects already built around runtime or compiled styling |
Choose one consistent styling approach for a project rather than mixing systems casually.
17. Accessibility Essentials
Section titled “17. Accessibility Essentials”Accessible HTML usually starts with choosing the correct native element.
function AccessibleForm() { const errorId = "email-error";
return ( <form> <label htmlFor="email">Email address</label> <input id="email" name="email" type="email" aria-describedby={errorId} required /> <p id={errorId}>Enter a valid email address.</p> <button type="submit">Subscribe</button> </form> );}| Do | Avoid |
|---|---|
Use <button> for actions | Clickable <div> elements |
| Associate labels with inputs | Placeholder-only form labels |
Add meaningful image alt text | Repeating decorative image details |
| Preserve keyboard focus visibility | Removing outlines without replacement |
Use aria-* only where needed | Replacing native semantics with ARIA |
For modal dialogs, menus, tabs, and comboboxes, use tested accessible component primitives or implement the full keyboard and focus behavior carefully.
18. Performance Tools
Section titled “18. Performance Tools”Start with clear code and measure actual slow interactions before memoizing.
useMemo: Cache a Calculation
Section titled “useMemo: Cache a Calculation”import { useMemo } from "react";
function ProductTable({ products, query }) { const visibleProducts = useMemo(() => { return products.filter((product) => product.name.toLowerCase().includes(query.toLowerCase()), ); }, [products, query]);
return visibleProducts.map((product) => ( <p key={product.id}>{product.name}</p> ));}useCallback and memo
Section titled “useCallback and memo”import { memo, useCallback, useState } from "react";
const SaveButton = memo(function SaveButton({ onSave }) { return ( <button type="button" onClick={onSave}> Save </button> );});
function Editor() { const [document, setDocument] = useState({ title: "" });
const handleSave = useCallback(() => { console.log("Saving", document); }, [document]);
return <SaveButton onSave={handleSave} />;}| Tool | Use It When |
|---|---|
memo(Component) | A component renders often with unchanged props and rendering is costly |
useMemo(fn, deps) | A measured expensive calculation repeats unnecessarily |
useCallback(fn, deps) | Stable function identity matters for a memoized child or dependency |
| Lazy loading | A route or heavy component need not ship immediately |
Memoization adds complexity and can be useless when props change each render. Profile first.
Lazy Load a Component
Section titled “Lazy Load a Component”import { lazy, Suspense } from "react";
const ReportsPage = lazy(() => import("./ReportsPage.jsx"));
function App() { return ( <Suspense fallback={<p>Loading report tools...</p>}> <ReportsPage /> </Suspense> );}19. TypeScript with React
Section titled “19. TypeScript with React”Type props, event handlers, and reusable children explicitly where it improves clarity.
type Product = { id: string; name: string; price: number;};
type ProductCardProps = { product: Product; onAddToCart: (productId: string) => void;};
export function ProductCard({ product, onAddToCart }: ProductCardProps) { return ( <article> <h2>{product.name}</h2> <p>${product.price.toFixed(2)}</p> <button type="button" onClick={() => onAddToCart(product.id)}> Add to cart </button> </article> );}Useful Types
Section titled “Useful Types”import type { ChangeEvent, FormEvent, ReactNode } from "react";
type PanelProps = { heading: string; children: ReactNode;};
function Panel({ heading, children }: PanelProps) { return ( <section> <h2>{heading}</h2> {children} </section> );}
function Search() { function handleChange(event: ChangeEvent<HTMLInputElement>) { console.log(event.target.value); }
function handleSubmit(event: FormEvent<HTMLFormElement>) { event.preventDefault(); }
return ( <form onSubmit={handleSubmit}> <input onChange={handleChange} /> </form> );}| Need | Type |
|---|---|
| Renderable nested content | ReactNode |
| Input change event | ChangeEvent<HTMLInputElement> |
| Form submit event | FormEvent<HTMLFormElement> |
| Button click event | MouseEvent<HTMLButtonElement> |
| DOM input ref | useRef<HTMLInputElement>(null) |
20. Testing Components
Section titled “20. Testing Components”Test what users observe and do: rendered text, labels, keyboard/click behavior, loading/error states, and outcomes of interactions.
import { useState } from "react";
export function Counter() { const [count, setCount] = useState(0);
return ( <> <p>Count: {count}</p> <button type="button" onClick={() => setCount((value) => value + 1)}> Increment </button> </> );}// Counter.test.jsx - example using Testing Library style APIsimport { render, screen } from "@testing-library/react";import userEvent from "@testing-library/user-event";import { Counter } from "./Counter";
test("increments the displayed count", async () => { const user = userEvent.setup(); render(<Counter />);
await user.click(screen.getByRole("button", { name: "Increment" }));
expect(screen.getByText("Count: 1")).toBeInTheDocument();});| Test | Verify |
|---|---|
| Rendering | Meaningful content and accessible roles appear |
| Interaction | Clicking, typing, or submitting changes visible behavior |
| Async state | Loading, success, empty, and error views work |
| Custom hook/reducer | Important state transitions are correct |
| Page flow | Critical user paths work across components |
Avoid asserting internal state variables or implementation details when a user-visible outcome expresses the requirement.
21. Error Boundaries and Resilience
Section titled “21. Error Boundaries and Resilience”An error boundary prevents a rendering error in part of the component tree from blanking the entire interface. Error boundaries are commonly supplied by a framework/router or implemented as a class component.
import { Component } from "react";
class ErrorBoundary extends Component { state = { hasError: false };
static getDerivedStateFromError() { return { hasError: true }; }
componentDidCatch(error, info) { console.error("UI rendering failed", error, info); }
render() { if (this.state.hasError) { return <p role="alert">Something went wrong. Please try again.</p>; }
return this.props.children; }}
function App() { return ( <ErrorBoundary> <Dashboard /> </ErrorBoundary> );}Error boundaries handle errors while rendering descendants, but they do not replace handling failed requests or errors inside event handlers.
22. Advanced State and UI Patterns
Section titled “22. Advanced State and UI Patterns”State Design Checklist
Section titled “State Design Checklist”| Question | Guidance |
|---|---|
| Can it be calculated from existing state/props? | Do not store it separately |
| Do several children edit it? | Lift it to their common parent |
| Is it shared deeply but changes infrequently? | Consider context |
| Does it have many named transitions? | Consider a reducer |
| Is it remote cached data? | Treat it as server state |
| Must it survive navigation or reload? | Store it in URL or persistence layer as appropriate |
Preserve or Reset State
Section titled “Preserve or Reset State”React preserves state while the same component remains in the same position. Use a key to intentionally reset a form when its identity changes:
function MessageEditor({ selectedContact }) { return <ChatForm key={selectedContact.id} contact={selectedContact} />;}Portals
Section titled “Portals”A portal renders UI into a different DOM container, useful for modal overlays and tooltips:
import { createPortal } from "react-dom";
function Modal({ children }) { return createPortal( <div className="modal-backdrop"> <div role="dialog" aria-modal="true"> {children} </div> </div>, document.body, );}Portals change DOM placement, not React ownership: context and React event handling still follow the React tree.
23. Common Mistakes and Fixes
Section titled “23. Common Mistakes and Fixes”| Mistake or Symptom | Cause | Fix |
|---|---|---|
| Component does not render | Name begins lowercase | Use function Profile() and <Profile /> |
| List input values move to wrong row | Unstable or index keys | Use persistent unique item IDs |
| UI does not update after array change | State was mutated | Return a new array/object |
| Infinite effect loop | Effect updates a changing dependency each run | Rethink synchronization and dependencies |
| Handler runs during rendering | Called it in JSX | Pass onClick={handleClick} or a callback |
| Input switches between controlled/uncontrolled | value starts undefined | Initialize to "" or consistently use uncontrolled input |
| Duplicate/out-of-date state | Derived data stored separately | Calculate from source state/props |
| Memoization everywhere but no speedup | Optimization added without measuring | Profile, then optimize the slow path |
Clicking a <div> is not keyboard accessible | Non-semantic interactive element | Use <button> or proper native element |
Avoid These Patterns
Section titled “Avoid These Patterns”// Wrong: mutating statetodos.push(newTodo);setTodos(todos);
// Correct: new arraysetTodos((current) => [...current, newTodo]);// Wrong: invokes immediately while rendering<button onClick={removeItem(id)}>Remove</button>
// Correct: invokes after click<button onClick={() => removeItem(id)}>Remove</button>24. Project Organization
Section titled “24. Project Organization”Start simple and group code by feature as an application grows.
src/ app/ App.jsx components/ Button.jsx Modal.jsx features/ cart/ CartButton.jsx CartPage.jsx useCart.js products/ ProductCard.jsx ProductsPage.jsx lib/ api.js styles/ globals.css| Guideline | Why |
|---|---|
| Keep files close to the feature using them | Changes are easier to understand |
Promote truly shared UI into components/ | Avoid premature global abstractions |
Put request clients and generic helpers in lib/ | Keep components focused on UI |
| Keep tests near feature code or in a consistent test tree | Make coverage discoverable |
Folder names matter less than predictable ownership and small, focused components.
25. Copy-Paste Recipes
Section titled “25. Copy-Paste Recipes”Basic Component
Section titled “Basic Component”export function Welcome({ name }) { return <h1>Welcome, {name}!</h1>;}Toggle
Section titled “Toggle”import { useState } from "react";
export function Toggle() { const [open, setOpen] = useState(false);
return ( <> <button type="button" onClick={() => setOpen((value) => !value)}> {open ? "Hide" : "Show"} details </button> {open && <p>More information here.</p>} </> );}Editable Input
Section titled “Editable Input”const [name, setName] = useState("");
<input value={name} onChange={(event) => setName(event.target.value)} />;Add an Item
Section titled “Add an Item”setItems((current) => [ ...current, { id: crypto.randomUUID(), title: newTitle },]);Update an Item
Section titled “Update an Item”setItems((current) => current.map((item) => item.id === editedItem.id ? { ...item, title: editedItem.title } : item, ),);Remove an Item
Section titled “Remove an Item”setItems((current) => current.filter((item) => item.id !== id));Effect Cleanup
Section titled “Effect Cleanup”useEffect(() => { const controller = new AbortController(); loadData({ signal: controller.signal }); return () => controller.abort();}, []);26. Learning Path and Quick Recall
Section titled “26. Learning Path and Quick Recall”Beginner
Section titled “Beginner”- Write components that return JSX.
- Pass data with props and render lists with stable keys.
- Handle clicks and input changes with
useState. - Build a controlled form and lift state between sibling components.
Intermediate
Section titled “Intermediate”- Synchronize with external systems using
useEffectand cleanup. - Use refs for DOM actions and context for carefully selected shared values.
- Move complicated transitions into
useReducer. - Extract reusable stateful logic into custom hooks.
- Test interactions and loading/error states from the user’s perspective.
Advanced
Section titled “Advanced”- Design state ownership deliberately: local, URL, context, reducer, or server state.
- Build reusable component APIs with composition and accessible behavior.
- Profile before using memoization or code splitting.
- Add error boundaries and resilient data/loading patterns.
- Integrate React with a routing and rendering architecture suited to the application.
Recall Card
Section titled “Recall Card”Component: function Card({ title }) { return <h2>{title}</h2>; }State: const [value, setValue] = useState(initialValue);Update prior: setCount((count) => count + 1);Event: <button onClick={handleClick}>Save</button>Input: <input value={name} onChange={(e) => setName(e.target.value)} />List: items.map((item) => <Row key={item.id} item={item} />)Conditional: ready ? <Result /> : <Loading />Effect: useEffect(() => { connect(); return disconnect; }, [roomId]);Ref: const inputRef = useRef(null);Context: const value = useContext(ThemeContext);Reducer: const [state, dispatch] = useReducer(reducer, initialState);Memoize: useMemo(() => expensiveWork(data), [data]);Lazy load: const Page = lazy(() => import("./Page.jsx"));