The Cheat Sheet
ContributeSearch
← FrameworksEdit this page

React

Practical reference for components, props, hooks, state, event handling, and patterns in React.

Components and Props

// Defining a component with destructured props & default values
function UserCard({ name, role = 'Member', children }) {
  return (
    <div className="card">
      <h3>{name}</h3>
      <p>{role}</p>
      {children}
    </div>
  );
}

// Using the component
export default function App() {
  return (
    <UserCard name="Ada Lovelace" role="Admin">
      <p>Logged in</p>
    </UserCard>
  );
}
  • Components must start with a capital letter and return JSX.
  • props are read-only inputs passed from parent to child.
  • children represents nested content passed inside the component tags.

JSX Syntax Basics

const title = 'React Cheat Sheet';
const isOnline = true;
const customStyle = { color: 'blue', fontSize: '14px' };

return (
  <>
    {/* Expression embedding */}
    <h1 style={customStyle}>{title}</h1>

    {/* Class names and HTML attributes use camelCase */}
    <div className="container" tabIndex={0}>
      <label htmlFor="search-input">Search:</label>
      <input id="search-input" disabled={!isOnline} />
    </div>
  </>
);
  • Use curly braces {} to embed any JavaScript expression.
  • Wrap adjacent elements in fragments (<>...</>) to return a single root element without adding extra DOM nodes.
  • Attribute names use camelCase (e.g. className, htmlFor, tabIndex, onClick).

State with useState

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  const [user, setUser] = useState({ name: 'Ada', age: 36 });

  // Update primitive state
  const increment = () => {
    // Use functional updater when next state depends on previous state
    setCount((prev) => prev + 1);
  };

  // Update object state immutably
  const updateAge = () => {
    setUser((prev) => ({ ...prev, age: prev.age + 1 }));
  };

  // Update array state immutably
  const [items, setItems] = useState(['a', 'b']);
  const addItem = (item) => setItems((prev) => [...prev, item]);
  const removeItem = (target) => setItems((prev) => prev.filter((i) => i !== target));

  return <button onClick={increment}>Count: {count}</button>;
}
  • Calling the state updater triggers a re-render.
  • Never mutate state directly (user.age = 37); always create a new copy.

Side Effects with useEffect

import { useState, useEffect } from 'react';

function Timer({ intervalMs }) {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const timerId = setInterval(() => {
      setSeconds((prev) => prev + 1);
    }, intervalMs);

    // Cleanup function runs on unmount or before effect re-runs
    return () => clearInterval(timerId);
  }, [intervalMs]); // Re-runs only when intervalMs changes

  return <p>Elapsed: {seconds}s</p>;
}
  • useEffect(fn) — runs after every render.
  • useEffect(fn, []) — runs once on mount (initial render).
  • useEffect(fn, [a, b]) — runs on mount and whenever a or b changes.
  • Return a cleanup function to unsubscribe, clear timers, or abort fetch requests.

Event Handling

function Form() {
  const [query, setQuery] = useState('');

  const handleChange = (e) => {
    setQuery(e.target.value);
  };

  const handleSubmit = (e) => {
    e.preventDefault(); // Prevent default browser form submission
    console.log('Submitted query:', query);
  };

  const handleDelete = (id, e) => {
    e.stopPropagation(); // Stop event bubbling
    console.log('Delete item:', id);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input value={query} onChange={handleChange} />
      <button type="submit">Search</button>
      <button type="button" onClick={(e) => handleDelete(42, e)}>
        Delete
      </button>
    </form>
  );
}
  • Pass event handlers as function references (onClick={handleClick}), not calls (onClick={handleClick()}).
  • Wrap in an arrow function to pass custom arguments: onClick={() => handleDelete(id)}.

Conditional Rendering

function Dashboard({ user, isLoading, error }) {
  // 1. Early return
  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      {/* 2. Ternary operator (if-else) */}
      {user ? <h2>Welcome, {user.name}!</h2> : <p>Please sign in.</p>}

      {/* 3. Logical AND (render only when truthy) */}
      {user?.isAdmin && <button>Admin Panel</button>}
    </div>
  );
}
  • Guard against rendering 0 with && (e.g. count > 0 && <Badge /> instead of count && <Badge />).

Lists and Keys

function UserList({ users }) {
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>
          <strong>{user.name}</strong> — {user.email}
        </li>
      ))}
    </ul>
  );
}
  • Always provide a stable, unique key prop on the top-level element returned by .map().
  • Use unique IDs (like database IDs) for keys. Avoid using array indexes if items can be reordered, inserted, or deleted.

Context API

import { createContext, useContext, useState } from 'react';

// 1. Create Context
const ThemeContext = createContext('light');

// 2. Provide Context
export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('dark');

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// 3. Consume Context
function ThemedButton() {
  const { theme, setTheme } = useContext(ThemeContext);

  return (
    <button
      onClick={() => setTheme((t) => (t === 'light' ? 'dark' : 'light'))}
    >
      Current theme: {theme}
    </button>
  );
}
  • Context lets you pass data deeply through the component tree without prop drilling.

Common Hooks

import { useRef, useMemo, useCallback } from 'react';

function HookExamples({ items, onSelect }) {
  // useRef: access DOM elements directly or persist mutable values across renders
  const inputRef = useRef(null);

  const focusInput = () => inputRef.current?.focus();

  // useMemo: cache the result of an expensive calculation
  const totalScore = useMemo(() => {
    return items.reduce((acc, item) => acc + item.score, 0);
  }, [items]);

  // useCallback: cache a function definition between renders
  const handleClick = useCallback(
    (id) => {
      onSelect(id);
    },
    [onSelect]
  );

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={focusInput}>Focus Input</button>
      <button onClick={() => handleClick(42)}>Select</button>
      <p>Total Score: {totalScore}</p>
    </div>
  );
}
  • useRef — stores DOM node references or mutable values that survive re-renders without triggering a new render.
  • useMemo — memoizes computed values until dependencies change.
  • useCallback — memoizes function instances passed to optimized child components.

Custom Hooks

import { useState, useEffect } from 'react';

// Custom hook to track window size (with SSR guard)
function useWindowSize() {
  const [size, setSize] = useState(() =>
    typeof window !== 'undefined'
      ? { width: window.innerWidth, height: window.innerHeight }
      : { width: 0, height: 0 }
  );

  useEffect(() => {
    const handleResize = () => {
      setSize({ width: window.innerWidth, height: window.innerHeight });
    };

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return size;
}

// Usage in a component
function ResponsiveView() {
  const { width } = useWindowSize();
  return <p>Window width: {width}px ({width > 768 ? 'Desktop' : 'Mobile'})</p>;
}
  • Custom hook names must start with use to allow React to enforce Rules of Hooks.
  • Used to extract and share stateful logic across multiple components.

References

Related Cheat Sheets