React Quick Reference
A quick lookup for React concepts and patterns grouped by category. All examples use function components and modern hooks (React 18+).
JSX Rules
Section titled “JSX Rules”| Rule | Correct | Wrong |
|---|---|---|
| Single root element | <><h1/><p/></> | <h1/><p/> |
| Self-close void elements | <input /> | <input> |
className not class | className="card" | class="card" |
htmlFor not for | htmlFor="id" | for="id" |
| camelCase events | onClick | onclick |
Expressions in {} | {count + 1} | — |
| Inline styles as object | style={{ color: 'red' }} | style="color:red" |
useState
Section titled “useState”const [value, setValue] = useState(initialValue);
// Set a new valuesetValue('new');
// Functional update — use when new state depends on previoussetValue(prev => prev + 1);
// Lazy initializer — only runs onceconst [data, setData] = useState(() => JSON.parse(localStorage.getItem('key') ?? 'null'));Never mutate state directly. Always pass a new value to the setter.
useEffect
Section titled “useEffect”// Run once on mountuseEffect(() => { fetchData();}, []);
// Run when dependency changesuseEffect(() => { document.title = `Page — ${name}`;}, [name]);
// With cleanup (timers, listeners, subscriptions)useEffect(() => { const id = setInterval(tick, 1000); return () => clearInterval(id);}, []);
// Async inside useEffectuseEffect(() => { async function load() { const res = await fetch('/api/data'); const json = await res.json(); setData(json); } load();}, []);Dependency array rules:
- Empty
[]— runs once after mount [a, b]— runs whenaorbchanges- No array — runs after every render (rarely correct)
- Include every reactive value the effect reads
useRef
Section titled “useRef”// DOM referenceconst inputRef = useRef(null);inputRef.current.focus();<input ref={inputRef} />
// Mutable value that does NOT trigger re-renderconst countRef = useRef(0);countRef.current++;useMemo
Section titled “useMemo”// Cache an expensive computationconst total = useMemo( () => items.reduce((sum, i) => sum + i.price, 0), [items] // only recompute when items changes);Use when the computation is measurably slow or when the result is passed to a React.memo child.
useCallback
Section titled “useCallback”// Cache a function referenceconst handleDelete = useCallback((id) => { setItems(prev => prev.filter(i => i.id !== id));}, []); // stable reference — no dependencies needed with functional setterUse when the function is passed to a React.memo component or listed in a useEffect dependency array.
useContext
Section titled “useContext”const value = useContext(MyContext);See the Context section below for the full pattern.
useReducer
Section titled “useReducer”function reducer(state, action) { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'reset': return { count: 0 }; default: return state; }}
const [state, dispatch] = useReducer(reducer, { count: 0 });
dispatch({ type: 'increment' });dispatch({ type: 'reset' });Prefer useReducer over multiple useState calls when state transitions are complex or interdependent.
Component Patterns
Section titled “Component Patterns”Function component
Section titled “Function component”export default function Card({ title, children }) { return ( <div className="card"> <h2>{title}</h2> {children} </div> );}// Passing<Card title="Housing" amount={1200} isActive />
// Receiving (destructure in parameter)function Card({ title, amount, isActive = false }) { ... }
// Spreadingfunction Input({ label, ...inputProps }) { return <><label>{label}</label><input {...inputProps} /></>;}Conditional rendering
Section titled “Conditional rendering”// Ternary — choose between two elements{isLoggedIn ? <Dashboard /> : <Login />}
// Logical AND — render or nothing (avoid with numbers — use count > 0 &&){hasItems && <ItemList items={items} />}
// Early returnif (isLoading) return <Spinner />;return <Content />;Lists and keys
Section titled “Lists and keys”{items.map(item => ( <Card key={item.id} item={item} /> // key on outermost element from map))}- Keys must be unique among siblings
- Keys must be stable — use IDs, not array indexes
- Keys are not accessible as props inside the component
children prop
Section titled “children prop”function Wrapper({ children }) { return <div className="wrapper">{children}</div>;}
<Wrapper> <p>Any content here becomes children.</p></Wrapper>Events
Section titled “Events”// Click<button onClick={handleClick}>Click</button><button onClick={() => handleClick(item.id)}>Delete</button>
// Form submit<form onSubmit={e => { e.preventDefault(); handleSubmit(); }}>
// Input change<input onChange={e => setValue(e.target.value)} value={value} />
// Checkbox<input type="checkbox" checked={agreed} onChange={e => setAgreed(e.target.checked)} />
// Key press<input onKeyDown={e => { if (e.key === 'Enter') save(); }} />| Common events | |
|---|---|
onClick | Mouse click |
onChange | Input/select value changed |
onSubmit | Form submitted |
onKeyDown / onKeyUp | Key pressed / released |
onFocus / onBlur | Element gains / loses focus |
onMouseEnter / onMouseLeave | Hover enter / leave |
Controlled Inputs
Section titled “Controlled Inputs”// Text / number inputconst [name, setName] = useState('');<input value={name} onChange={e => setName(e.target.value)} />
// Selectconst [category, setCategory] = useState('');<select value={category} onChange={e => setCategory(e.target.value)}> <option value="">Select…</option> {options.map(o => <option key={o.id} value={o.id}>{o.label}</option>)}</select>
// Checkboxconst [agreed, setAgreed] = useState(false);<input type="checkbox" checked={agreed} onChange={e => setAgreed(e.target.checked)} />State Patterns
Section titled “State Patterns”Adding to an array
Section titled “Adding to an array”setItems(prev => [...prev, newItem]);Removing from an array
Section titled “Removing from an array”setItems(prev => prev.filter(i => i.id !== id));Updating one item in an array
Section titled “Updating one item in an array”setItems(prev => prev.map(i => i.id === id ? { ...i, ...updates } : i));Updating a property in an object
Section titled “Updating a property in an object”setState(prev => ({ ...prev, name: 'new name' }));Never mutate: state.name = 'new' or items.push(x) will not trigger re-renders.
Performance
Section titled “Performance”React.memo
Section titled “React.memo”import { memo } from 'react';
const Card = memo(function Card({ item }) { return <div>{item.name}</div>;});Skips re-render if all props are unchanged (by reference). Pair with useCallback for function props and useMemo for object/array props to prevent reference changes.
The memoization triad
Section titled “The memoization triad”| Tool | What it caches | Use when |
|---|---|---|
React.memo | Component render | Child receives stable props but parent re-renders often |
useMemo | A computed value | Expensive calculation; value passed to a React.memo child |
useCallback | A function reference | Function passed to a React.memo child or used in useEffect deps |
Measure before applying. These tools have overhead — don’t add them by default.
Context API
Section titled “Context API”// 1. Createconst ThemeContext = createContext(null);
// 2. Providerfunction ThemeProvider({ children }) { const [theme, setTheme] = useState('dark'); return ( <ThemeContext.Provider value={{ theme, setTheme }}> {children} </ThemeContext.Provider> );}
// 3. Custom hook (recommended pattern)function useTheme() { const ctx = useContext(ThemeContext); if (!ctx) throw new Error('useTheme must be used inside ThemeProvider'); return ctx;}
// 4. Consumefunction Button() { const { theme } = useTheme(); return <button className={theme}>Click</button>;}
// 5. Wire up<ThemeProvider> <App /></ThemeProvider>Custom Hooks
Section titled “Custom Hooks”// Convention: function name starts with "use"function useLocalStorage(key, initialValue) { const [value, setValue] = useState(() => { try { const item = localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch { return initialValue; } });
const set = (next) => { const v = next instanceof Function ? next(value) : next; setValue(v); localStorage.setItem(key, JSON.stringify(v)); };
return [value, set];}
// Usage — drop-in replacement for useStateconst [name, setName] = useLocalStorage('name', '');Rules that apply to custom hooks:
- Must start with
use - Can call other hooks
- Cannot be called conditionally or inside loops
Common Patterns
Section titled “Common Patterns”Data fetching
Section titled “Data fetching”const [data, setData] = useState(null);const [loading, setLoading] = useState(true);const [error, setError] = useState(null);
useEffect(() => { const controller = new AbortController(); async function fetch() { try { const res = await fetch('/api/data', { signal: controller.signal }); if (!res.ok) throw new Error('Request failed'); setData(await res.json()); } catch (err) { if (err.name !== 'AbortError') setError(err.message); } finally { setLoading(false); } } fetch(); return () => controller.abort();}, []);Derived state (compute, don’t store)
Section titled “Derived state (compute, don’t store)”// Don't do this:const [total, setTotal] = useState(0);useEffect(() => setTotal(items.reduce(...)), [items]);
// Do this — compute during render:const total = items.reduce((sum, i) => sum + i.price, 0);Lifting state up
Section titled “Lifting state up”When two siblings need shared data, move state to their nearest common ancestor and pass data + callbacks as props.
function Parent() { const [items, setItems] = useState([]);
function addItem(item) { setItems(prev => [...prev, item]); }
return ( <> <Form onAdd={addItem} /> <List items={items} /> </> );}