React / Next.js Cheatsheet
Quick reference for React patterns in Next.js. Keep this open during your interview.
Client vs Server Components
Component Types
1// SERVER COMPONENT (default in Next.js 13+)2// - Can fetch data directly3// - Cannot use useState, useEffect, onClick4// - Runs on the server56export default async function Page() {7 const data = await fetch("http://api.example.com/data")8 return <div>{data}</div>9}1011// CLIENT COMPONENT12// - Add "use client" at the top13// - Can use hooks and event handlers14// - Runs in the browser1516"use client"1718import { useState } from "react"1920export default function Counter() {21 const [count, setCount] = useState(0)22 return <button onClick={() => setCount(count + 1)}>{count}</button>23}
useState
useState
1"use client"2import { useState } from "react"34// Basic usage5const [count, setCount] = useState(0)6const [name, setName] = useState("")7const [items, setItems] = useState<Item[]>([])8const [user, setUser] = useState<User | null>(null)910// Updating state11setCount(5) // Set to value12setCount(prev => prev + 1) // Functional update (safer)13setItems([...items, newItem]) // Add to array14setItems(items.filter(i => i.id !== id)) // Remove from array15setItems(items.map(i => i.id === id ? updated : i)) // Update in array
useEffect
useEffect
1"use client"2import { useEffect } from "react"34// Run once on mount5useEffect(() => {6 fetchData()7}, [])89// Run when dependency changes10useEffect(() => {11 fetchUser(userId)12}, [userId])1314// Cleanup on unmount15useEffect(() => {16 const ws = new WebSocket("ws://...")1718 return () => {19 ws.close() // Cleanup function20 }21}, [])2223// Common pattern: fetch data24useEffect(() => {25 const fetchData = async () => {26 setLoading(true)27 try {28 const res = await fetch("/api/items")29 const data = await res.json()30 setItems(data)31 } catch (err) {32 setError(err.message)33 } finally {34 setLoading(false)35 }36 }37 fetchData()38}, [])
Fetching Data
fetch() Patterns
1// GET request2const res = await fetch("http://localhost:8000/api/items")3const data = await res.json()45// POST request6const res = await fetch("http://localhost:8000/api/items", {7 method: "POST",8 headers: { "Content-Type": "application/json" },9 body: JSON.stringify({ name: "New Item" }),10})11const created = await res.json()1213// PATCH request14const res = await fetch(`http://localhost:8000/api/items/${id}`, {15 method: "PATCH",16 headers: { "Content-Type": "application/json" },17 body: JSON.stringify({ completed: true }),18})1920// DELETE request21await fetch(`http://localhost:8000/api/items/${id}`, {22 method: "DELETE",23})
Form Handling
Form Pattern
1"use client"23export default function Form() {4 const [name, setName] = useState("")5 const [email, setEmail] = useState("")67 const handleSubmit = async (e: React.FormEvent) => {8 e.preventDefault() // CRITICAL: Prevents page reload!910 await fetch("/api/users", {11 method: "POST",12 headers: { "Content-Type": "application/json" },13 body: JSON.stringify({ name, email }),14 })1516 setName("") // Clear form17 setEmail("")18 }1920 return (21 <form onSubmit={handleSubmit}>22 <input23 type="text"24 value={name}25 onChange={(e) => setName(e.target.value)}26 placeholder="Name"27 />28 <input29 type="email"30 value={email}31 onChange={(e) => setEmail(e.target.value)}32 placeholder="Email"33 />34 <button type="submit">Submit</button>35 </form>36 )37}
List Rendering
List Rendering
1// ALWAYS include a unique key prop!2{items.map((item) => (3 <div key={item.id}>4 {item.name}5 </div>6))}78// With index (only if items have no unique ID)9{items.map((item, index) => (10 <div key={index}>{item}</div>11))}1213// Conditional rendering in list14{items.map((item) => (15 <div key={item.id}>16 {item.completed && <span>✓</span>}17 {item.name}18 </div>19))}
Conditional Rendering
Conditional Rendering
1// Loading state2{loading && <p>Loading...</p>}34// Error state5{error && <p className="text-red-500">{error}</p>}67// Ternary for either/or8{isLoggedIn ? <Dashboard /> : <Login />}910// Empty state11{items.length === 0 ? (12 <p>No items yet</p>13) : (14 <ItemList items={items} />15)}1617// Multiple conditions18{loading ? (19 <Spinner />20) : error ? (21 <Error message={error} />22) : (23 <Content data={data} />24)}
useRef
useRef
1import { useRef, useEffect } from "react"23// DOM reference4const inputRef = useRef<HTMLInputElement>(null)56// Focus on mount7useEffect(() => {8 inputRef.current?.focus()9}, [])1011// In JSX12<input ref={inputRef} />1314// Mutable value (doesn't trigger re-render)15const wsRef = useRef<WebSocket | null>(null)1617useEffect(() => {18 wsRef.current = new WebSocket("ws://...")1920 return () => {21 wsRef.current?.close()22 }23}, [])
TypeScript Types
TypeScript
1// Define your types2interface Item {3 id: number4 name: string5 completed: boolean6}78interface User {9 id: number10 email: string11 name: string | null12}1314// Use with useState15const [items, setItems] = useState<Item[]>([])16const [user, setUser] = useState<User | null>(null)1718// Event types19const handleClick = (e: React.MouseEvent) => {}20const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {}21const handleSubmit = (e: React.FormEvent) => {}2223// Props types24interface ButtonProps {25 label: string26 onClick: () => void27 disabled?: boolean28}2930function Button({ label, onClick, disabled = false }: ButtonProps) {31 return <button onClick={onClick} disabled={disabled}>{label}</button>32}
Next.js File Structure
App Router Structure
1app/2 page.tsx # Route: /3 layout.tsx # Shared layout4 loading.tsx # Loading UI5 error.tsx # Error UI67 about/8 page.tsx # Route: /about910 products/11 page.tsx # Route: /products12 [id]/13 page.tsx # Route: /products/1231415 api/16 items/17 route.ts # API: /api/items