React Cheat Sheet
JSX, components and props, conditions and lists, state updates, events and forms, effects, refs, reducers, context, custom hooks, performance, TypeScript, routing and testing.
Updated
Project and entry point#
npm create vite@latest my-app -- --template react # or react-ts
cd my-app && npm install && npm run dev// src/main.jsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.jsx";
createRoot(document.getElementById("root")).render(
<StrictMode>
<App />
</StrictMode>,
);JSX#
const name = "Asha";
const element = (
<>
<h1 className="title">Hello, {name}!</h1>
<label htmlFor="q">Search</label>
<input id="q" maxLength={40} />
<p style={{ color: "teal", fontSize: 18 }}>Inline style object</p>
{/* a comment */}
<img src="/logo.png" alt="Logo" />
</>
);{ } holds expressions, not statements. Use className, htmlFor, camelCase attributes, self-closing tags, and one root (or a fragment <>...</>).
Components and props#
function Card({ title, price = 0, children }) { // destructure, with a default
return (
<section>
<h3>{title}</h3>
<p>₹{price}</p>
{children}
</section>
);
}
<Card title="Lamp" price={799}>
<button>Buy</button>
</Card>;Names start with a capital letter. Props are read-only. Strings in quotes, other values in braces.
Conditions and lists#
{isLoggedIn ? <Dashboard /> : <Login />}
{hasError && <p className="error">{message}</p>}
{count > 0 && <Badge count={count} />} // not {count && ...}: 0 renders
{items.map((item) => (
<li key={item.id}>{item.name}</li> // stable, unique keys
))}State#
import { useState } from "react";
const [count, setCount] = useState(0);
setCount(count + 1);
setCount((c) => c + 1); // updater: based on the latest value
const [user, setUser] = useState({ name: "Ravi", city: "Pune" });
setUser({ ...user, city: "Delhi" }); // copy, don't mutate
const [items, setItems] = useState([]);
setItems([...items, newItem]); // add
setItems(items.filter((i) => i.id !== id)); // remove
setItems(items.map((i) => (i.id === id ? { ...i, done: true } : i))); // updateEvents and forms#
<button onClick={handleClick}>Save</button>
<button onClick={() => remove(id)}>Delete</button> // pass arguments with an arrow
<input value={text} onChange={(e) => setText(e.target.value)} />
<input type="checkbox" checked={agree} onChange={(e) => setAgree(e.target.checked)} />
<select value={plan} onChange={(e) => setPlan(e.target.value)}>...</select>
function handleSubmit(e) {
e.preventDefault(); // stop the page reload
}
<form onSubmit={handleSubmit}>...</form>Effects#
import { useEffect } from "react";
useEffect(() => {
const id = setInterval(tick, 1000);
return () => clearInterval(id); // cleanup
}, []); // [] once · [a, b] when they change · none: every render
useEffect(() => {
let ignore = false;
fetch(`/api/users/${userId}`)
.then((res) => res.json())
.then((data) => { if (!ignore) setUser(data); });
return () => { ignore = true; }; // ignore stale responses
}, [userId]);Don't use effects to compute values from props or state; compute them during rendering.
Refs, reducers and context#
import { createContext, useContext, useReducer, useRef } from "react";
const inputRef = useRef(null);
<input ref={inputRef} />;
inputRef.current.focus(); // in a handler or effect
function reducer(state, action) {
switch (action.type) {
case "added": return [...state, action.item];
case "removed": return state.filter((i) => i.id !== action.id);
default: throw new Error(`Unknown action: ${action.type}`);
}
}
const [list, dispatch] = useReducer(reducer, []);
dispatch({ type: "added", item });
const ThemeContext = createContext("light");
<ThemeContext value="dark"><Page /></ThemeContext>; // React 19 (older: ThemeContext.Provider)
const theme = useContext(ThemeContext);Custom hooks#
function useToggle(initial = false) {
const [on, setOn] = useState(initial);
return [on, () => setOn((v) => !v)];
}
const [open, toggleOpen] = useToggle();Names start with use. Each call has its own state. Hooks only at the top level of components and hooks.
Performance#
import { memo, useCallback, useMemo } from "react";
const Row = memo(function Row({ item, onSelect }) { /* ... */ });
const sorted = useMemo(() => items.toSorted(compare), [items]);
const handleSelect = useCallback((id) => setSelected(id), []);Measure with the React DevTools Profiler first. The React Compiler can add memoisation automatically.
TypeScript#
import type { ChangeEvent, ReactNode } from "react";
type ButtonProps = { label: string; onClick?: () => void; children?: ReactNode };
function Button({ label, onClick }: ButtonProps) {
return <button onClick={onClick}>{label}</button>;
}
const [user, setUser] = useState<User | null>(null);
const ref = useRef<HTMLInputElement>(null);
function handleChange(e: ChangeEvent<HTMLInputElement>) {}Routing (React Router)#
import { BrowserRouter, Link, Route, Routes, useNavigate, useParams } from "react-router";
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="products/:id" element={<Product />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>;
<Link to="/products/3">Silk saree</Link>;
const { id } = useParams(); // a string
const navigate = useNavigate(); navigate("/cart");Testing (Vitest + Testing Library)#
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
test("increments", async () => {
const user = userEvent.setup();
render(<Counter />);
await user.click(screen.getByRole("button", { name: "Increment" }));
expect(screen.getByText("Count: 1")).toBeInTheDocument();
});getBy must exist now · queryBy may be absent · findBy waits (async).
Common pitfalls#
onClick={fn()}calls the function during render; useonClick={fn}oronClick={() => fn(x)}.- Mutating state (
push,obj.x = 1) doesn't re-render; create new objects and arrays. - Missing effect dependencies cause stale values; missing cleanup leaks timers and listeners.
- Index or random keys break list updates; use stable ids.
- Defining components inside components resets their state on every render.
Want the full explanations? Go to the Learn React course →