How to Debug a React Application in VS Code (Complete Guide)
Step-by-step guide to debugging React apps in VS Code: component errors, hooks bugs, state issues, and network failures, using DevTools and the VS Code debugger.
React Debugging Happens in Two Places
React apps have two debugging environments: browser DevTools for component state, network, and runtime errors, and VS Code for breakpoints and step-through debugging. Both are useful for different problems.
Use browser DevTools for:
- Reading error messages and component stacks
- Inspecting state and props in React DevTools
- Watching network requests
- Console logging
Use VS Code debugger for:
- Setting breakpoints in event handlers and useEffect
- Stepping through complex logic line by line
- Inspecting variable state without console.log spam
Step 1: Read the Error Overlay
React dev mode shows a red error overlay with the component stack when an unhandled error occurs. The component stack reads bottom-up:
Start from ProductCard at line 18. Go to that line, that is where the error fires. The parent, ProductList line 34, is where ProductCard received the undefined prop.
Step 2: Install React DevTools
React DevTools is a browser extension for Chrome and Firefox that adds two panels to DevTools:
- Components: see the full component tree, inspect each component's props and state in real time
- Profiler: record a session and see which components re-rendered and how long they took
For props and state bugs, open the Components panel, click the component, and see current state on the right. Change state directly to test behavior without modifying code.
Tip: In the Components panel, right-click a component and select "Log this component's data to the console". This gives you a full snapshot of props and state as a JS object, which is easier to inspect for complex nested state.
Step 3: Set Up VS Code Debugger for React
Create .vscode/launch.json in your project root:
Start your dev server with npm run dev, then press F5 in VS Code. Chrome launches controlled by VS Code. Set breakpoints in .jsx or .tsx files and execution pauses in VS Code when that line runs.
Note: For Vite-based projects, the url port is 5173 not 3000. Check your terminal for the correct port.
Step 4: Debug useEffect
useEffect is the most common source of React bugs. Common patterns:
Fix: Always include a dependency array. Primitives like string, number, and boolean are safe. Objects and arrays need
useMemoor should be moved inside the effect.
Set a breakpoint inside useEffect to see how many times it runs:
Remove debugger before committing. It is a fast way to check effect frequency without adding console.log.
Step 5: Debug State Issues
When state looks wrong, the problem is almost always one of three things.
Stale Closure
Fix: Use the functional update form, or include count in the dependency array.
State Mutation
Fix: Always return new references.
Step 6: Debug Network Requests
Open DevTools, go to the Network tab, and filter by "Fetch/XHR". Every API call your React app makes appears here.
For each failed request, check:
- Status code: 401 means auth, 422 means validation, 500 means server error
- Response body: the actual error message from the server
- Request headers: is the Authorization header present and in the correct format?
- Request body: is the payload what you expected?
Tip: Click a request and select "Copy as cURL", then paste it in the terminal. This reproduces the exact request outside the browser. If it works in the terminal but fails in the browser, the issue is CORS or an auth header.
Step 7: Debug Custom Hooks
Custom hooks are functions. Debug them like functions. Add a breakpoint at the first line of the hook, or return debug info alongside the main return value:
In the React DevTools Components panel, find the component using the hook. Its state shows the hook's state values directly.
Common React Errors Quick Reference
| Error | Likely cause | First check |
|---|---|---|
| Cannot read properties of undefined | Prop is undefined, accessing property too early | Check parent passes prop, add optional chaining |
| Each child in a list should have a unique key | List rendered without stable key | Add key={item.id}, not array index |
| Infinite re-render | useEffect dependency causes re-render which triggers effect | Check effect dependencies, memoize objects |
| Stale data in handler | Stale closure capturing old state | Use functional update setState(prev => ...) |
| Component does not update | State mutation | Return new array or object instead of mutating |
| Rendered more hooks than previous render | Hooks called conditionally | Move hook calls before any early returns |
For cross-component state bugs where state passes through 3 or more components and arrives wrong at the bottom, paste the component tree into DebugAI. It reads the prop-drilling chain and identifies where the value changes or gets lost.
Debug faster starting today.
Free VS Code extension. 10 sessions/day. No credit card.