React Cheatsheet
Context
Use this React reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
What Context Does
Context lets you pass data through the component tree without prop drilling. Any component that calls useContext gets the value without intermediaries needing to forward it.
Use context for global or subtree-wide data: theme, locale, current user, auth state. Avoid it for frequently changing data (every consumer re-renders) — use a state manager instead.
createContext
import { createContext } from 'react'; // Signature: createContext(defaultValue) // defaultValue is used only when a component has NO Provider above it const ThemeContext = createContext('light'); // string default const UserContext = createContext(null); // null default const CountContext = createContext({ count: 0, increment: () => {} });
Provider
Wrap the subtree that needs access to the value.
import { createContext, useState } from 'react'; export const ThemeContext = createContext('light'); export function ThemeProvider({ children }) { const [theme, setTheme] = useState('light'); const toggleTheme = () => setTheme(prev => prev === 'light' ? 'dark' : 'light'); return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> {children} </ThemeContext.Provider> ); }
React 19 shorthand — render the context object itself as the provider (.Provider still works but is no longer needed):
// React 19+ return ( <ThemeContext value={{ theme, toggleTheme }}> {children} </ThemeContext> );
// Wrap at the appropriate level (root, page, or section) import { ThemeProvider } from './ThemeContext'; function App() { return ( <ThemeProvider> <Header /> <Main /> </ThemeProvider> ); }
useContext
Read the context value in any descendant.
import { useContext } from 'react'; import { ThemeContext } from './ThemeContext'; function ThemeToggle() { const { theme, toggleTheme } = useContext(ThemeContext); return ( <button onClick={toggleTheme}> Switch to {theme === 'light' ? 'dark' : 'light'} mode </button> ); } // The component re-renders whenever the context VALUE changes
use(Context) — Conditional Reads (React 19)
use reads a context like useContext, but it may be called inside conditionals and loops (it must still be inside a component or hook).
import { use } from 'react'; import { ThemeContext } from './ThemeContext'; function Heading({ children, level }) { if (level > 3) { return <h4>{children}</h4>; // early return BEFORE reading context — fine } const theme = use(ThemeContext); // useContext could not be called here return <h1 className={theme}>{children}</h1>; }
Full Pattern: Context + Custom Hook
Export a custom hook to:
- Hide the useContext import detail
- Provide a helpful error when used outside the provider
// AuthContext.jsx import { createContext, useContext, useState } from 'react'; const AuthContext = createContext(null); export function AuthProvider({ children }) { const [user, setUser] = useState(null); const login = async (email, password) => { const res = await fetch('/api/login', { method: 'POST', body: JSON.stringify({ email, password }), headers: { 'Content-Type': 'application/json' }, }); const data = await res.json(); setUser(data.user); }; const logout = () => setUser(null); return ( <AuthContext.Provider value={{ user, login, logout }}> {children} </AuthContext.Provider> ); } // Custom hook — throws if used outside provider export function useAuth() { const ctx = useContext(AuthContext); if (ctx === null) throw new Error('useAuth must be used within AuthProvider'); return ctx; } // Usage in any descendant function Profile() { const { user, logout } = useAuth(); return ( <> <p>Hello, {user?.name}</p> <button onClick={logout}>Log out</button> </> ); }
Updating Context
The Provider's value is just a prop — updating parent state updates all consumers.
export const CartContext = createContext(null); export function CartProvider({ children }) { const [items, setItems] = useState([]); const addItem = (item) => setItems(prev => [...prev, item]); const removeItem = (id) => setItems(prev => prev.filter(i => i.id !== id)); const clearCart = () => setItems([]); const total = items.reduce((sum, i) => sum + i.price * i.qty, 0); return ( <CartContext.Provider value={{ items, addItem, removeItem, clearCart, total }}> {children} </CartContext.Provider> ); }
Nesting Multiple Providers
function App() { return ( <AuthProvider> <ThemeProvider> <CartProvider> <Router /> </CartProvider> </ThemeProvider> </AuthProvider> ); }
Context Without State (Static Values)
// Config, feature flags, etc. — never changes, no re-renders const FeatureFlagContext = createContext({}); function App() { const flags = { newDashboard: true, betaSearch: false }; return ( <FeatureFlagContext.Provider value={flags}> <Router /> </FeatureFlagContext.Provider> ); }
Default Value Behavior
const UserContext = createContext({ name: 'Guest', role: 'viewer' }); // Component with no Provider ancestor gets the default value directly function Standalone() { const user = useContext(UserContext); // { name: 'Guest', role: 'viewer' } return <p>{user.name}</p>; }
The default value is useful for testing components in isolation — render without a Provider and get predictable defaults.
Optimizing Re-renders
Every consumer re-renders when the value prop changes reference. Avoid creating new objects on each parent render.
// BAD — new object every render triggers all consumers function ThemeProvider({ children }) { const [theme, setTheme] = useState('light'); return ( // { theme, setTheme } is a new object each render <ThemeContext.Provider value={{ theme, setTheme }}> {children} </ThemeContext.Provider> ); } // GOOD — memoize the value object import { useMemo } from 'react'; function ThemeProvider({ children }) { const [theme, setTheme] = useState('light'); const value = useMemo( () => ({ theme, setTheme }), [theme] ); return ( <ThemeContext.Provider value={value}> {children} </ThemeContext.Provider> ); }
Split contexts by update frequency — separate read-only state from dispatch to avoid over-rendering:
const StoreStateContext = createContext(null); // data const StoreDispatchContext = createContext(null); // actions — stable reference function StoreProvider({ children }) { const [state, dispatch] = useReducer(reducer, initialState); return ( <StoreDispatchContext.Provider value={dispatch}> <StoreStateContext.Provider value={state}> {children} </StoreStateContext.Provider> </StoreDispatchContext.Provider> ); } // Components that only dispatch never re-render on state changes function DeleteButton({ id }) { const dispatch = useContext(StoreDispatchContext); return <button onClick={() => dispatch({ type: 'delete', id })}>Delete</button>; }
Context vs State Management Libraries
| Context + useReducer | Zustand / Jotai / Redux | |
|---|---|---|
| Setup | Built-in, no deps | Extra package |
| DevTools | Basic | Rich time-travel tools |
| Perf at scale | Re-renders all consumers | Granular subscriptions |
| Use when | Low-freq global state | Complex / high-freq state |
Common Built-in Contexts (React)
// Not exported by React — these are examples of commonly built contexts // React itself only has one built-in context: used by Profiler internally // Common patterns you'll build yourself: // ThemeContext — 'light' | 'dark' + toggle // AuthContext — user, login(), logout() // LocaleContext — 'en' | 'fr' + translations // RouterContext — (used internally by React Router) // ToastContext — addToast(msg), removeToast(id)