React Cheatsheet
More Hooks
Use this React reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
useRef
Stores a mutable value that does not trigger re-renders. Also used to access DOM nodes.
import { useRef, useEffect } from 'react'; // DOM reference function TextInput() { const inputRef = useRef(null); // initial value: null const focus = () => inputRef.current.focus(); return ( <> <input ref={inputRef} /> <button onClick={focus}>Focus</button> </> ); } // Mutable instance variable (persists across renders, no re-render on change) function Timer() { const intervalRef = useRef(null); const [count, setCount] = useState(0); const start = () => { intervalRef.current = setInterval(() => setCount(c => c + 1), 1000); }; const stop = () => clearInterval(intervalRef.current); return <><p>{count}</p><button onClick={start}>Start</button><button onClick={stop}>Stop</button></>; } // Hold previous value of a prop/state function usePrevious(value) { const prev = useRef(undefined); useEffect(() => { prev.current = value; }); return prev.current; // returns value from previous render }
ref.current is read/written directly; mutating it is fine and does not cause re-renders.
useReducer
Alternative to useState when state logic is complex or involves multiple sub-values.
import { useReducer } from 'react'; // 1. Define a reducer — pure function (state, action) => newState function counterReducer(state, action) { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; case 'reset': return { count: 0 }; case 'set': return { count: action.payload }; default: throw new Error('Unknown action: ' + action.type); } } // 2. Use it function Counter() { const [state, dispatch] = useReducer(counterReducer, { count: 0 }); return ( <div> <p>{state.count}</p> <button onClick={() => dispatch({ type: 'increment' })}>+</button> <button onClick={() => dispatch({ type: 'decrement' })}>-</button> <button onClick={() => dispatch({ type: 'set', payload: 10 })}>Set 10</button> </div> ); } // Lazy initializer (third arg) — runs once const [state, dispatch] = useReducer(reducer, userId, (id) => ({ user: null, loading: true, id }));
useMemo
Memoize an expensive computation — recomputes only when dependencies change.
import { useMemo } from 'react'; function FilteredList({ items, query }) { // Recomputes only when items or query changes const filtered = useMemo( () => items.filter(i => i.name.includes(query)), [items, query] ); return <ul>{filtered.map(i => <li key={i.id}>{i.name}</li>)}</ul>; } // Stable object reference (avoids re-renders of memoized children) const options = useMemo(() => ({ threshold: 0.5 }), []); // stable forever
Do not overuse.
useMemoitself has a cost. Only memoize when a profiler shows the computation is actually slow, or when you need a stable reference.
useCallback
Memoize a function reference — returns the same function instance until deps change.
import { useCallback } from 'react'; function Parent({ userId }) { const [items, setItems] = useState([]); // Without useCallback, a new function is created every render → // memoized children (React.memo) would still re-render const handleDelete = useCallback( (id) => setItems(prev => prev.filter(i => i.id !== id)), [] // setItems is stable, so no deps needed ); return <MemoizedList items={items} onDelete={handleDelete} />; } // Equivalent: useMemo returning a function const handleDelete = useMemo( () => (id) => setItems(prev => prev.filter(i => i.id !== id)), [] );
useCallback(fn, deps)is sugar foruseMemo(() => fn, deps).
useContext
Read a context value. (See Context page for createContext and Provider.)
import { useContext } from 'react'; import { ThemeContext } from './ThemeContext'; function Button({ children }) { const { theme, toggleTheme } = useContext(ThemeContext); return ( <button className={theme === 'dark' ? 'btn-dark' : 'btn-light'} onClick={toggleTheme} > {children} </button> ); }
useId
Generate a stable, unique ID per component instance. Use for accessibility attributes.
import { useId } from 'react'; function LabeledInput({ label }) { const id = useId(); // e.g. "«r3»" (React 19; React 18 generated ":r3:") return ( <div> <label htmlFor={id}>{label}</label> <input id={id} /> </div> ); } // Safe for SSR — same ID generated on server and client
useTransition
Mark state updates as non-urgent (can be interrupted by urgent updates).
import { useTransition } from 'react'; function Search() { const [query, setQuery] = useState(''); const [results, setResults] = useState([]); const [isPending, startTransition] = useTransition(); const handleChange = (e) => { setQuery(e.target.value); // urgent — update input immediately startTransition(() => { setResults(computeResults(e.target.value)); // non-urgent — can defer }); }; return ( <> <input value={query} onChange={handleChange} /> {isPending && <Spinner />} <ResultsList results={results} /> </> ); }
useDeferredValue
Defer a value (not the setter) — the UI renders with the old value while the new one loads.
import { useDeferredValue } from 'react'; function SearchResults({ query }) { const deferredQuery = useDeferredValue(query); // deferredQuery lags behind query — heavy list renders with stale value const isStale = deferredQuery !== query; return ( <div style={{ opacity: isStale ? 0.5 : 1 }}> <HeavyList query={deferredQuery} /> </div> ); }
useImperativeHandle
Customize the handle a parent gets from a component's ref. In React 19, ref is a regular prop on function components, so no forwardRef wrapper is needed.
import { useImperativeHandle, useRef } from 'react'; // React 19 — ref arrives as a normal prop function VideoPlayer({ src, ref }) { const videoRef = useRef(null); useImperativeHandle(ref, () => ({ play: () => videoRef.current.play(), pause: () => videoRef.current.pause(), seek: (time) => { videoRef.current.currentTime = time; }, })); return <video ref={videoRef} src={src} />; } // React ≤18 (legacy): wrap in forwardRef to receive ref — // const VideoPlayer = forwardRef(function VideoPlayer(props, ref) { ... }); // Parent function App() { const playerRef = useRef(null); return ( <> <VideoPlayer ref={playerRef} src="/movie.mp4" /> <button onClick={() => playerRef.current.play()}>Play</button> </> ); }
useDebugValue
Label a custom hook in React DevTools.
import { useDebugValue, useState } from 'react'; function useOnlineStatus() { const [online, setOnline] = useState(navigator.onLine); // Shows "OnlineStatus: Online" in DevTools useDebugValue(online ? 'Online' : 'Offline'); return online; } // With formatter (deferred — only called when DevTools are open) useDebugValue(date, (d) => d.toISOString());
useSyncExternalStore
Subscribe to an external store (non-React state). The correct way to integrate third-party stores.
import { useSyncExternalStore } from 'react'; // Works with any store that exposes subscribe + getSnapshot function useWindowWidth() { return useSyncExternalStore( (callback) => { window.addEventListener('resize', callback); return () => window.removeEventListener('resize', callback); }, () => window.innerWidth, // client snapshot () => 1024 // server snapshot (SSR) ); }
Hook Rules
- Only call hooks at the top level — never inside conditions, loops, or nested functions.
- Only call hooks from React function components or custom hooks — not regular JS functions.
// WRONG — inside a condition if (condition) { const [x, setX] = useState(0); // violates rule 1 } // CORRECT — always at top level; condition goes inside the hook const [x, setX] = useState(0); if (condition) { setX(1); } // eslint-plugin-react-hooks enforces these rules automatically
Hooks Quick Reference
| Hook | Purpose |
|---|---|
useState | Local state with re-render |
useReducer | Complex state machine |
useEffect | Side effects (fetch, listeners, timers) |
useLayoutEffect | Side effects before paint |
useRef | DOM ref / mutable value without re-render |
useContext | Read context value |
useMemo | Memoize expensive computation |
useCallback | Stable function reference |
useId | Unique accessible ID |
useTransition | Mark update as non-urgent |
useDeferredValue | Defer a derived value |
useImperativeHandle | Customize the handle exposed via ref |
useDebugValue | DevTools label for custom hooks |
useSyncExternalStore | Subscribe to external store |
useActionState | Form/action state + pending flag (React 19 — see Forms) |
useOptimistic | Optimistic value while an action runs (React 19 — see Forms) |
use | Read a promise or context in render (React 19) |