React Cheat Sheet: A Practical Quick Reference

After years of writing React, I’ve noticed that most daily work boils down to a handful of patterns repeated over and over. This cheat sheet captures the syntax and idioms I actually reach for — not the theory, but the code I type when building real features.

Components: The Atom of React

Modern React is functional. Forget classes unless you’re maintaining legacy code or writing an Error Boundary.

jsx
// Function component — the default
function Welcome({ name }) {
  return <h1>Hello, {name}</h1>;
}

// Arrow form — equally common
const Welcome = ({ name }) => <h1>Hello, {name}</h1>;

export default Welcome;

A component is just a function that takes props and returns JSX. That’s the whole mental model.

Hooks: Where the Logic Lives

useState — Local State

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

// Direct update
setCount(count + 1);

// Functional update — use when next state depends on previous
setCount((prev) => prev + 1);

Rule of thumb: if the new state depends on the old state, use the functional form. It avoids stale closure bugs.

useEffect — Side Effects

jsx
useEffect(() => {
  const id = setInterval(tick, 1000);
  return () => clearInterval(id); // cleanup
}, [tick]);

The dependency array tells React when to re-run:

  • [] — once on mount
  • [a, b] — when a or b changes
  • omitted — every render (almost always a bug)

useRef — Mutable Values Without Re-rendering

jsx
const inputRef = useRef(null);

useEffect(() => {
  inputRef.current.focus();
}, []);

return <input ref={inputRef} />;

useRef is also great for holding any mutable value that shouldn’t trigger re-renders — timer IDs, previous props, etc.

useMemo and useCallback — Performance

jsx
// Memoize expensive computations
const sorted = useMemo(() => items.sort(compare), [items]);

// Memoize callbacks passed to memoized children
const handleClick = useCallback((id) => deleteItem(id), [deleteItem]);

Don’t sprinkle these everywhere. Only reach for them when you have a measured performance problem or you’re passing functions/objects to React.memo components.

useContext — Avoiding Prop Drilling

jsx
const ThemeContext = createContext("light");

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <div className={theme}>...</div>;
}

useReducer — Complex State

jsx
function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "reset":
      return { count: 0 };
    default:
      throw new Error();
  }
}

const [state, dispatch] = useReducer(reducer, { count: 0 });
dispatch({ type: "increment" });

Reach for useReducer when state transitions become complex or when multiple related values change together.

JSX Patterns You’ll Use Every Day

Conditional Rendering

jsx
{
  isLoggedIn && <Dashboard />;
}
{
  isLoggedIn ? <Dashboard /> : <Login />;
}
{
  user?.name ?? "Guest";
}

List Rendering

jsx
{
  todos.map((todo) => <li key={todo.id}>{todo.text}</li>);
}

Always use a stable key. Don’t use the array index unless the list never reorders.

Spreading Props

jsx
<Input {...commonProps} value={value} onChange={onChange} />

Fragments

jsx
<>
  <Header />
  <Main />
</>

Controlled Forms

jsx
function LoginForm() {
  const [email, setEmail] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    submit(email);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <button type="submit">Login</button>
    </form>
  );
}

Three rules: value is bound to state, onChange updates state, onSubmit calls preventDefault.

Custom Hooks: Your Reusability Tool

Anything that starts with use and calls other hooks is a custom hook. Extract logic, not markup.

jsx
function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let cancelled = false;
    fetch(url)
      .then((r) => r.json())
      .then((d) => {
        if (!cancelled) setData(d);
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [url]);

  return { data, loading };
}

The cancelled flag prevents state updates after the component unmounts — a common subtle bug.

Performance Tools

jsx
// Skip re-renders when props are shallow-equal
const Card = React.memo(function Card({ title }) {
  return <div>{title}</div>;
});

// Code-split a heavy component
const Editor = React.lazy(() => import("./Editor"));

<Suspense fallback={<Spinner />}>
  <Editor />
</Suspense>;

Routing with React Router v6

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

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/users/:id" element={<User />} />
      </Routes>
    </BrowserRouter>
  );
}

function User() {
  const { id } = useParams();
  const navigate = useNavigate();
  return <button onClick={() => navigate("/")}>Back</button>;
}

Common Gotchas

Stale closures. When a function captures state, it captures it at render time. If you read it later, you get the old value. Fix with the functional update form, or by reading from a ref.

Effects firing twice in dev. React 18+ runs effects twice in Strict Mode to catch missing cleanup. This is intentional — make your effects idempotent.

Mutating state directly. Always create a new object/array. arr.push(x) won’t trigger a re-render; setArr([...arr, x]) will.

Forgetting key on lists. React uses key to identify which items changed. Without it, you get subtle bugs around inputs, animations, and component state.

Project Structure I Tend Toward

text
src/
  components/    # Shared, reusable UI
  pages/         # Route-level components
  hooks/         # Custom hooks
  contexts/      # React context providers
  api/           # Network layer
  utils/         # Pure helpers

The exact names matter less than picking a structure and sticking with it.

Closing Thought

React is small at its core: components, props, state, effects. Most of what makes a codebase pleasant or painful isn’t React itself — it’s how disciplined you are about keeping components small, effects narrow, and state local. When in doubt, lift state up only as far as it needs to go, and not one level higher.