React Cheatsheet
Frontend
16 views
Apr 2026
React Cheatsheet
Component Basics
// Function component
function Hello({ name, age = 0 }) {
return <h1>Hello, {name}! Age: {age}</h1>;
}
export default function App() {
return <Hello name="Alice" age={30} />;
}
// Fragments (avoid extra DOM node)
function List() {
return (
<>
<li>Item 1</li>
<li>Item 2</li>
</>
);
}
// Conditional rendering
function Status({ isOnline }) {
return (
<span>
{isOnline ? "Online" : "Offline"}
{isOnline && <span className="dot green" />}
</span>
);
}
// List rendering — key must be stable!
function Items({ items }) {
return (
<ul>
{items.map((item, i) => (
<li key={item}>{i+1}. {item}</li>
))}
</ul>
);
}
useState
import { useState } from "react";
// Primitive state
const [count, setCount] = useState(0);
const [name, setName] = useState("Alice");
// Object state — always spread, never mutate
const [user, setUser] = useState({ name: "Alice", age: 30 });
setUser(prev => ({ ...prev, age: 31 }));
// Array state
const [items, setItems] = useState([]);
setItems(prev => [...prev, "new item"]);
setItems(prev => prev.filter(i => i !== "remove this"));
// Lazy initializer
const [data, setData] = useState(() => computeExpensiveValue());
// Toggle
setActive(prev => !prev);
useEffect
import { useEffect } from "react";
// Run once on mount
useEffect(() => {
fetchData();
}, []);
// Run when dep changes
useEffect(() => {
document.title = "Count: " + count;
}, [count]);
// Cleanup (timers, subscriptions, listeners)
useEffect(() => {
const id = setInterval(() => setCount(c => c + 1), 1000);
return () => clearInterval(id);
}, []);
// Fetch with abort / cancel guard
useEffect(() => {
let cancelled = false;
async function load() {
const data = await fetchUser(userId);
if (!cancelled) setUser(data);
}
load();
return () => { cancelled = true; };
}, [userId]);
useRef, useMemo, useCallback
import { useRef, useMemo, useCallback } from "react";
// useRef — DOM access
const inputRef = useRef(null);
inputRef.current?.focus();
// useRef — persistent mutable value (no re-render)
const countRef = useRef(0);
countRef.current++;
// useMemo — expensive computation
const sorted = useMemo(
() => [...items].sort((a, b) => a.price - b.price),
[items]
);
// useCallback — stable function reference
const handleDelete = useCallback(
(id) => dispatch(deleteItem(id)),
[dispatch]
);
useContext
import { createContext, useContext, useState } from "react";
const ThemeContext = createContext(null);
// Provider component
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
const toggle = () => setTheme(t => t === "light" ? "dark" : "light");
return (
<ThemeContext.Provider value={{ theme, toggle }}>
{children}
</ThemeContext.Provider>
);
}
// Custom hook
function useTheme() {
const ctx = useContext(ThemeContext);
if (!ctx) throw new Error("useTheme must be inside ThemeProvider");
return ctx;
}
// Consumer
function Button() {
const { theme, toggle } = useTheme();
return <button className={theme} onClick={toggle}>Toggle</button>;
}
useReducer
import { useReducer } from "react";
function reducer(state, action) {
switch (action.type) {
case "increment": return { ...state, count: state.count + state.step };
case "decrement": return { ...state, count: state.count - state.step };
case "reset": return { count: 0, step: state.step };
case "setStep": return { ...state, step: action.payload };
default: return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0, step: 1 });
return (
<>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</>
);
}
Custom Hooks
// useFetch
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let cancelled = false;
setLoading(true);
fetch(url)
.then(r => r.json())
.then(d => { if (!cancelled) { setData(d); setLoading(false); } })
.catch(e => { if (!cancelled) { setError(e); setLoading(false); } });
return () => { cancelled = true; };
}, [url]);
return { data, loading, error };
}
// useDebounce
function useDebounce(value, delay = 300) {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const id = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(id);
}, [value, delay]);
return debounced;
}
// useLocalStorage
function useLocalStorage(key, initial) {
const [value, setValue] = useState(() => {
try {
const stored = localStorage.getItem(key);
return stored !== null ? JSON.parse(stored) : initial;
} catch { return initial; }
});
const set = useCallback((v) => {
setValue(prev => {
const next = typeof v === "function" ? v(prev) : v;
localStorage.setItem(key, JSON.stringify(next));
return next;
});
}, [key]);
return [value, set];
}
Performance
// React.memo — skip re-render if props unchanged
const ExpensiveChild = React.memo(function Child({ data }) {
return <div>{data}</div>;
});
// lazy + Suspense — code splitting
const HeavyPage = React.lazy(() => import("./HeavyPage"));
function App() {
return (
<Suspense fallback={<Spinner />}>
<HeavyPage />
</Suspense>
);
}
// useTransition — non-urgent update
const [isPending, startTransition] = useTransition();
startTransition(() => setFilteredList(expensiveFilter(input)));
// useDeferredValue
const deferred = useDeferredValue(searchQuery);
Patterns & Best Practices
// Prop drilling alternative: composition
function Layout({ header, sidebar, children }) {
return (
<div className="layout">
<header>{header}</header>
<aside>{sidebar}</aside>
<main>{children}</main>
</div>
);
}
// Error boundary (class component still needed)
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() { return { hasError: true }; }
componentDidCatch(error, info) { console.error(error, info); }
render() {
return this.state.hasError
? <h1>Something went wrong.</h1>
: this.props.children;
}
}
// forwardRef
const Input = React.forwardRef(({ label, ...props }, ref) => (
<label>
{label}
<input ref={ref} {...props} />
</label>
));
// useImperativeHandle
React.useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus(),
clear: () => setvalue("")
}));