React Cheat Sheet: The Practical Version

Most React cheat sheets are useless. They list every hook with a one-line description and leave you to figure out the actual work. I spent three years building React apps that crashed in production, so here is the version I actually use. This isn't a comprehensive reference. It is the stuff you reach for when your component won't update, your layout shifts, or you spend two hours debugging something that should have taken twenty minutes. State management in React follows a simple rule that most tutorials ignore: useState does not merge objects, it replaces them. If you have a state object like { name: "Alex", age: 29 } and you call setState({ name: "Bob" }), age disappears. The spread operator is not optional here. You need setState(prev => ({ ...prev, name: "Bob" })). I learned this the hard way when a user profile form lost the timezone field on every keystroke because I forgot to spread the previous state.

useEffect runs after render, not before. That means if you are fetching data inside useEffect, your component will always render once with empty data before the request completes. This is normal, not a bug. The fix is either an isLoading flag or an initial state value. Here is the pattern I use: const [data, setData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { fetch('/api/data').then(res => res.json()).then(result => { setData(result); setLoading(false); }); }, []);

The empty dependency array means this runs once on mount. If you omit it, the effect runs on every render and you will hammer your API or create an infinite loop. I once had a production dashboard that re-fetched every single component update because someone added a callback dependency without realizing it recreated on every render. Took me forty-five minutes to find it. Context is not a global state solution. It is a prop drilling avoidance tool. The performance cost comes from re-rendering every consumer whenever any value in the context changes, even if they only use one field. Split your contexts. I keep a ThemeContext for colors and fonts, and a separate DataContext for API state. They live on different providers and they only re-render when their own values change. Keys in lists are not just for performance. React uses them to track which items have changed, been added, or removed. Using array indices as keys works for static lists but breaks when items reorder or get filtered. I use stable IDs from the data source. When I cannot use an ID, I use a combination like `${item.category}-${item.name}`. Never use Math.random(). I learned this when a Todo app started deleting the wrong items after filtering because the keys shifted on every render.

Get the Full Details

React Cheat Sheet: Quick Refrence Guide
React Cheat Sheet: Quick Refrence Guide

For forms, controlled components are straightforward until you have twenty fields. I switch to react-hook-form for anything beyond a simple login screen. It reduces boilerplate, handles validation, and avoids re-rendering the entire form on every keystroke. The defaultValues prop accepts an object that pre-populates the form. Here is a minimal setup: const { register, handleSubmit } = useForm(); onSubmit={data => console.log(data)} Custom hooks are where React gets powerful. Any function starting with use is a hook. The convention is that they encapsulate logic, not JSX. I have a useDebounce hook that wraps setTimeout and returns the debounced value. I have a useLocalStorage hook that reads and writes to localStorage with JSON serialization. These live in a hooks folder and get reused across components.

Performance optimization usually comes down to three things: memoizing expensive calculations with useMemo, preventing unnecessary re-renders with React.memo, and avoiding inline object or function creation in JSX. Inline functions create new references on every render, which breaks memoization in child components. I pass handlers defined outside the component or wrapped in useCallback when they need closures. Virtualized lists are the workaround for long lists. Rendering five hundred rows in the DOM will freeze your browser. Libraries like react-window solve this by only rendering what is visible in the viewport. The difference is night and day. A list that took three seconds to load dropped to under two hundred milliseconds with virtualization. It only makes sense for large datasets though. Adding this complexity to a list of twenty items is overkill. Server-side rendering with Next.js is the standard for production React apps now. It handles routing, API calls, and SEO without the manual setup that React Router required a few years ago. The tradeoff is lock-in. Your code needs to work on the server and the client, which means no window references, no browser-only APIs, and careful handling of useEffect with SSR. I run into hydration mismatches about once a month when a component renders different content on the server versus the client. The error message tells you exactly what mismatched, but finding the root cause can take a while.

Testing React components is simpler than people make it. React Testing Library focuses on user behavior, not implementation details. Don't test that a button has a specific className. Test that clicking the button triggers the expected action. The act and expect pattern covers most cases: render(); fireEvent.click(screen.getByRole('button')); expect(screen.getByText('Success')).toBeInTheDocument(); Mocking API calls with MSW (Mock Service Worker) saves you from hitting real endpoints during tests. I set it up once in a test helper and reuse it across the suite. Runs take about three seconds per file instead of fifteen when the tests were calling the development server.

React Cheat Sheet & Quick Reference
React Cheat Sheet & Quick Reference

Here is the cheat sheet itself, the stuff I actually reference when I am stuck. Not everything React can do. Just what I need when I need it. useState - manages local component state. Returns a value and a setter function. Initial value can be a direct value or a lazy initializer function. useEffect - runs side effects after render. Accepts a callback and optional dependencies. Returns an optional cleanup function.

useContext - reads a context value without prop drilling. Needs a Context object created with createContext(). useReducer - alternative to useState for complex state logic. Takes a reducer function and initial state. Returns [state, dispatch]. useMemo - memoizes expensive calculations. Only recomputes when dependencies change.

useCallback - memoizes function references. Prevents child component re-renders from inline handler recreation. useRef - holds a mutable value that persists across renders without triggering re-renders. Also accesses DOM elements directly. Custom Hook Pattern - extract logic into a function prefixed with use. Return values and handlers. Can call other hooks inside.

React - Js Cheat Sheet: Quick Learning | PDF | Computer Engineering ...
React - Js Cheat Sheet: Quick Learning | PDF | Computer Engineering ...

React.memo - wraps a component to skip re-renders when props have not changed. Shallow comparison by default. Fragment - JSX wrapper that does not add a DOM element. Written as <> Conditional Rendering - use && for simple truthy checks. Ternary operators for more complex branches. Avoid rendering undefined or null as JSX elements.

Lifting State Up - when two components need shared state, move it to their closest common parent. Pass it down as props. Prop Drilling - passing props through multiple component levels. Solved with Context, state management libraries, or composition with children props. There are parts of React that this cheat sheet does not cover well. Server components, concurrent features, and the newer use() hook for reading promises are areas where the documentation is still catching up. I have hit cases where Concurrent Mode features behave unexpectedly in older browsers because they rely on features that fall back to older patterns silently. Check your target support matrix before adopting these features aggressively.

The biggest gap in most React guides is error handling. React has error boundaries that catch rendering errors in child components. You define a class component with componentDidCatch or getDerivedStateFromError. They do not catch errors in event handlers, asynchronous code, or server-side rendering. I wrap my main app tree in an error boundary that shows a fallback UI and logs to Sentry. It prevents the entire app from going white when a single component crashes. Bundle size matters more than people admit. React itself is small but the ecosystem adds up fast. Tree shaking removes unused code only if the library supports it properly. I check bundlephobia.com before adding any package. react-query is 14kb gzipped but Redux with middleware can easily exceed 50kb. For small projects, the context plus useReducer combination replaces most Redux use cases with zero additional dependency weight. I keep this document open in a tab when I start new projects. Not to read it cover to cover, but to grab the patterns I consistently forget. The one about useState not merging objects saved me from another form bug last week.

React Cheat Sheet 2025 : React Testing Library Cheat Sheet For 2025 ...
React Cheat Sheet 2025 : React Testing Library Cheat Sheet For 2025 ...