React cheat sheet

A scannable React reference: 13 short snippets across 6 topics, each linking back to the lesson it came from.

At a glance

TopicWhat it covers
Components and propsThe key is React's identity tag for an element between renders. It must be stable and unique among siblings — alesson
State with hooksuseState and useReducer, batched updates, immutable updates for objects and arrays, and deriving values instead oflesson
Effects and data fetchinguseEffect dependencies and cleanup, why fetching in an effect has sharp edges, and what production code does insteadlesson
Setting up a React project with ViteScaffold with create-vite, understand the folder layout, how Fast Refresh and the automatic JSX transform work, and thelesson
Testing React componentsA test written through roles and labels fails when the component becomes inaccessible, which is exactly the feedbacklesson
Production builds, environment config and deploymentWhat Vite emits, route-level code splitting, why VITE_ variables are public, SPA rewrites on static hosts, bundlelesson

Quick snippets

Components and props

Props are read-only

function Price({ amount, currency = 'USD', onSelect }) {
  return (
    <button onClick={() => onSelect(amount)}>
      {currency} {amount.toFixed(2)}
    </button>
  )
}

// pass a value, a function, or an element
<Price amount={19.5} currency="EUR" onSelect={addToCart} />
<Card header={<Title>Invoice</Title>} />

Lists and keys

function GuideList({ guides }) {
  return (
    <ul>
      {guides.map(guide => (
        <li key={guide.id}>
          <a href={'/guides/' + guide.slug}>{guide.title}</a>
        </li>
      ))}
    </ul>
  )
}

Full lesson: Components and props →

State with hooks

useState and the rules of updates

// immutable updates: build a new object / array, never mutate the old one
const [form, setForm] = useState({ email: '', name: '' })
setForm(prev => ({ ...prev, email: '[email protected]' }))     // object merge

const [tags, setTags] = useState([])
setTags(prev => [...prev, 'new'])                    // append
setTags(prev => prev.filter(t => t !== 'new'))       // remove
setTags(prev => prev.map(t => (t === 'x' ? 'y' : t)))  // replace

Full lesson: State with hooks →

Effects and data fetching

Effects and their dependencies

import { useState, useEffect } from 'react'

function Clock() {
  const [now, setNow] = useState(() => new Date())

  useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 1000)
    return () => clearInterval(id)      // cleanup runs on unmount and before re-running
  }, [])                                // empty array: set up once

  return <time>{now.toLocaleTimeString()}</time>
}

Effects and their dependencies

useEffect(() => {
  const controller = new AbortController()
  fetch(url, { signal: controller.signal })
    .then(r => r.json())
    .then(setData)
    .catch(e => { if (e.name !== 'AbortError') setError(e) })
  return () => controller.abort()
}, [url])

What production code does instead

// a query library owns cache, retries, deduplication and refetching
const { data, isPending, error } = useQuery({
  queryKey: ['guide', slug],
  queryFn: ({ signal }) => fetchGuide(slug, signal),
  staleTime: 60_000
})

// mutations declare what becomes stale afterwards
const publish = useMutation({
  mutationFn: (id) => fetch('/api/publish/' + id, { method: 'POST' }),
  onSuccess: () => queryClient.invalidateQueries({ queryKey: ['guides'] })
})

Full lesson: Effects and data fetching →

Setting up a React project with Vite

Scaffold and layout

// src/main.tsx - the single entry point of the application
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import './index.css'

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>
)

TypeScript, lint and formatting

// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  server: { port: 5173, open: true },
  build: { sourcemap: true },
  resolve: { alias: { '@': new URL('./src', import.meta.url).pathname } }
})

Full lesson: Setting up a React project with Vite →

Testing React components

Accessibility and a smoke test

// assert the accessibility contract, not just the DOM structure
expect(screen.getByRole('dialog')).toHaveAttribute('aria-modal', 'true')
expect(screen.getByRole('button', { name: 'Close' })).toBeEnabled()
expect(screen.getByLabelText('Email')).toHaveFocus()

// run an accessibility audit over the rendered tree
import { axe } from 'vitest-axe'

test('the signup form has no accessibility violations', async () => {
  const { container } = render(<SignupForm />)
  expect(await axe(container)).toHaveNoViolations()
})

Accessibility and a smoke test

// a Playwright smoke test covers the built application end to end
import { expect, test } from '@playwright/test'

test('the home page loads and links to the guides', async ({ page }) => {
  await page.goto('http://localhost:4173')       // the preview server output
  await expect(page.getByRole('heading', { name: /guides/i })).toBeVisible()
  await page.getByRole('link', { name: /guides/i }).click()
  await expect(page).toHaveURL(/guides/)
})

Full lesson: Testing React components →

Production builds, environment config and deployment

Build output and code splitting

import { lazy } from 'react'

// route-level splitting is the highest-value split: the chunk is fetched on first visit
const Settings = lazy(() => import('./routes/Settings'))

// keep heavy, rarely used pieces out of the entry chunk too
const Chart = lazy(() => import('./components/Chart'))

// Vite creates a chunk per dynamic import, named from the module path,
// so a large feature becomes a download the user pays for only if they use it

Environment variables that behave

// src/config.js - read once, validate once, fail loudly
const apiUrl = import.meta.env.VITE_API_URL
if (!apiUrl) {
  throw new Error('VITE_API_URL is required')
}

export const API_URL = apiUrl
export const isProduction = import.meta.env.PROD

Rewrites, analysis and monitoring

# inspect what is actually inside each chunk before shipping
npx vite-bundle-visualizer

# a build with the production environment, so the analysis matches production
npm run build -- --mode production

Full lesson: Production builds, environment config and deployment →

FAQ

Is this React cheat sheet free to use?
Yes. No sign-up and no tracking: the page is static, every example is on the page itself, and you can print it or save it as a one-page reference.
Where do the examples come from?
Every snippet is taken from the 6 lessons of the React course on this site, and each section links back to the lesson it was pulled from.
How do I go deeper than a cheat sheet?
Open the full React course — it carries the worked explanations, the edge cases and the exercises behind every line here.

HTML CSS JavaScript TypeScript HTML DOM AJAX

Last refreshed 2026-09-27.