React Cheatsheet
Hooks, component patterns, context, refs, and performance tips for building React applications.
Component Basics
Function component
function Hello({ name }: { name: string }) {
return <h1>Hello, {name}!</h1>;
}Default props via destructuring
function Button({ label = "Click me", onClick }) {
return <button onClick={onClick}>{label}</button>;
}Children prop
function Card({ children }: { children: React.ReactNode }) {
return <div className="card">{children}</div>;
}Conditional rendering
{isLoading ? <Spinner /> : <Content />}
{error && <ErrorBanner message={error} />}List rendering
{items.map((item) => (
<ListItem key={item.id} item={item} />
))}Core Hooks
useState
const [count, setCount] = useState(0);
// functional update
setCount(prev => prev + 1);useEffect
useEffect(() => {
document.title = `Count: ${count}`;
return () => { /* cleanup */ };
}, [count]); // dependency arrayuseRef
const inputRef = useRef<HTMLInputElement>(null);
// access DOM
inputRef.current?.focus();useMemo
const sorted = useMemo(
() => [...items].sort((a, b) => a.name.localeCompare(b.name)),
[items]
);useCallback
const handleClick = useCallback(() => {
doSomething(id);
}, [id]);useReducer
const [state, dispatch] = useReducer(reducer, initialState);
dispatch({ type: "INCREMENT" });Context
Create context
const ThemeContext = createContext<"light" | "dark">("light");Provide value
<ThemeContext.Provider value={theme}>
<App />
</ThemeContext.Provider>Consume
const theme = useContext(ThemeContext);Custom hook wrapper
function useTheme() {
const ctx = useContext(ThemeContext);
if (!ctx) throw new Error("useTheme must be used inside ThemeProvider");
return ctx;
}Custom Hooks
useLocalStorage
function useLocalStorage<T>(key: string, initial: T) {
const [value, setValue] = useState<T>(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initial;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue] as const;
}useDebounce
function useDebounce<T>(value: T, delay: number): T {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const t = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(t);
}, [value, delay]);
return debounced;
}useFetch
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url).then(r => r.json()).then(setData).finally(() => setLoading(false));
}, [url]);
return { data, loading };
}Performance
React.memo
const MemoCard = React.memo(Card);
// re-renders only when props changeLazy loading
const HeavyChart = lazy(() => import("./HeavyChart"));
<Suspense fallback={<Spinner />}>
<HeavyChart />
</Suspense>Avoid inline objects as props
// Bad: creates new object every render
<Comp style={{ color: "red" }} />
// Good
const style = { color: "red" };
<Comp style={style} />Key prop matters
// Bad: index as key causes bugs on reorder
items.map((item, i) => <Row key={i} />)
// Good
items.map(item => <Row key={item.id} />)Event Handling
Click
<button onClick={(e) => handleClick(e)}>Click</button>Form submit
<form onSubmit={(e) => {
e.preventDefault();
handleSubmit();
}}>Input change
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>Keyboard
<input onKeyDown={(e) => {
if (e.key === "Enter") handleEnter();
}} />#hooks#context#components#performance