Skip to main content

Debugging React Apps with Cursor: Tools, Tips, and Workflows

Cursor React Debugging

Debugging React applications can be challenging due to component hierarchies, state management complexity, and asynchronous data flows. Cursor's integrated debugging tools and AI assistance make identifying and fixing issues faster. This guide covers React-specific debugging workflows.

Prerequisites​

Before starting:

  • Cursor installed (latest version)
  • React project set up
  • React DevTools browser extension installed (optional but recommended)

Setting Up Debugging in Cursor​

Launch Configuration​

Create .vscode/launch.json for React debugging:

{
"version": "0.2.0",
"configurations": [
{
"name": "Debug React App",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}",
"sourceMapPathOverrides": {
"webpack:///src/*": "${webRoot}/src/*"
}
},
{
"name": "Debug Next.js",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "dev"],
"env": {
"NODE_OPTIONS": "--inspect"
},
"console": "integratedTerminal"
}
]
}

Source Maps​

Ensure source maps are enabled in your build config:

// vite.config.ts
export default defineConfig({
build: {
sourcemap: true,
},
});

// next.config.js
const nextConfig = {
productionBrowserSourceMaps: true,
};
module.exports = nextConfig;

Debugging React Components​

Breakpoints in JSX​

Set breakpoints directly in your component files:

// src/components/UserProfile.tsx
import { useState, useEffect } from 'react';

export function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);

useEffect(() => {
async function fetchUser() {
setLoading(true);
const response = await fetch(`/api/users/${userId}`);
// Set breakpoint here
const data = await response.json();
setUser(data);
setLoading(false);
}

fetchUser();
}, [userId]);

if (loading) return <div>Loading...</div>;
if (!user) return <div>User not found</div>;

return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}

Conditional Breakpoints​

Right-click on a breakpoint to set conditions:

Condition: userId === "12345"

The breakpoint only triggers when the condition is met.

State Debugging Techniques​

Console Logging with Context​

Use Cursor's AI to add strategic logs:

Add console.log statements to trace the state changes in this component

Cursor adds:

useEffect(() => {
console.log('[UserProfile] userId changed:', userId);

async function fetchUser() {
console.log('[UserProfile] fetching user...');
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
console.log('[UserProfile] received data:', data);
setUser(data);
}

fetchUser();
}, [userId]);

React DevTools Integration​

While React DevTools runs in the browser, you can reference component data in Cursor:

  1. Open React DevTools in your browser
  2. Inspect the component tree
  3. Copy the component props/state
  4. Paste into Cursor chat for analysis
This component is re-rendering infinitely. Here are the props and state from DevTools:
[paste data]

What's causing the loop?

Hooks Troubleshooting​

useEffect Dependencies​

Common issue: missing or incorrect dependency arrays.

// Before - buggy
useEffect(() => {
fetchData(query);
}, []); // Missing dependency

// After - fixed
useEffect(() => {
fetchData(query);
}, [query]); // Correct dependency

Ask Cursor to audit your hooks:

Review all useEffect hooks in this file for missing dependencies

Custom Hook Debugging​

// src/hooks/useLocalStorage.ts
import { useState, useEffect, useCallback } from 'react';

export function useLocalStorage<T>(key: string, initialValue: T) {
// Get stored value
const [storedValue, setStoredValue] = useState<T>(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(`Error reading localStorage key "${key}":`, error);
return initialValue;
}
});

// Return a wrapped version of useState's setter
const setValue = useCallback(
(value: T | ((val: T) => T)) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(`Error setting localStorage key "${key}":`, error);
}
},
[key, storedValue]
);

return [storedValue, setValue] as const;
}
Hooks Rule Violations

Cursor can detect common hooks violations like calling hooks conditionally or inside loops. Use the linter integration to catch these early.

Next.js Debugging​

Server-Side Debugging​

Debug API routes and server components:

{
"name": "Debug Next.js Server",
"type": "node",
"request": "launch",
"runtimeExecutable": "npx",
"runtimeArgs": ["next", "dev"],
"env": {
"NODE_OPTIONS": "--inspect=9230"
},
"port": 9230
}

API Route Breakpoints​

// app/api/users/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
// Set breakpoint here
const users = await prisma.user.findMany();

// Inspect users in debugger
return NextResponse.json({ users });
}

Client-Side vs Server-Side​

ContextDebugging Approach
Client ComponentsChrome DevTools, React DevTools
Server ComponentsNode.js debugger in Cursor
API RoutesNode.js debugger
MiddlewareConsole logs + Node.js debugger

Common React Issues and Fixes​

Infinite Re-renders​

Symptom: Browser freezes, console shows repeated logs.

// Problem: new object reference on every render
function Parent() {
const [count, setCount] = useState(0);

return (
<Child config={{ limit: 10 }} /> // New object every render!
);
}

// Solution: memoize the config
function Parent() {
const [count, setCount] = useState(0);
const config = useMemo(() => ({ limit: 10 }), []);

return <Child config={config} />;
}

Stale Closures​

// Problem: callback captures old state
function Counter() {
const [count, setCount] = useState(0);

const logCount = useCallback(() => {
console.log(count); // Always logs initial value
}, []); // Missing dependency

// Solution: use functional updates or include dependency
const logCountFixed = useCallback(() => {
console.log(count);
}, [count]);
}

Memory Leaks​

// Problem: state update after unmount
useEffect(() => {
let isMounted = true;

fetchData().then(data => {
if (isMounted) {
setData(data);
}
});

return () => {
isMounted = false;
};
}, []);

Using Cursor AI for Debugging​

Error Analysis​

Paste error messages into Cursor:

I'm getting this error in my React app:
"Cannot read properties of undefined (reading 'map')"

Here's the component code:
[paste code]

What's wrong and how do I fix it?

Performance Debugging​

This component renders slowly. Here's the code and a React DevTools profiler screenshot:
[paste code]

How can I optimize it?

Common optimizations Cursor suggests:

  • Memoize expensive computations with useMemo
  • Prevent unnecessary re-renders with React.memo
  • Virtualize long lists
  • Split large components

State Management Debugging​

Redux DevTools​

Configure Redux DevTools in development:

// store.ts
import { configureStore } from '@reduxjs/toolkit';

export const store = configureStore({
reducer: {
user: userReducer,
cart: cartReducer,
},
devTools: process.env.NODE_ENV !== 'production',
});

Zustand Store Inspection​

// Debug Zustand store
import { useUserStore } from './stores/userStore';

// In browser console
const userStore = useUserStore.getState();
console.log(userStore);

Testing Components Before Debugging​

// src/components/__tests__/UserProfile.test.tsx
import { render, screen, waitFor } from '@testing-library/react';
import { UserProfile } from '../UserProfile';

describe('UserProfile', () => {
it('handles loading state', () => {
render(<UserProfile userId="1" />);
expect(screen.getByText('Loading...')).toBeInTheDocument();
});

it('handles error state', async () => {
render(<UserProfile userId="invalid" />);
await waitFor(() => {
expect(screen.getByText('User not found')).toBeInTheDocument();
});
});
});

Debugging Checklist​

IssueFirst Check
Component not renderingCheck conditional returns and loading states
State not updatingVerify setState calls and dependency arrays
Props undefinedCheck parent component prop passing
API call failsInspect network tab and error boundaries
Slow performanceCheck for unnecessary re-renders
Type errorsVerify TypeScript interfaces match data

Keyboard Shortcuts for Debugging​

ActionShortcut
Toggle breakpointF9
Start debuggingF5
Step overF10
Step intoF11
Step outShift + F11
ContinueF5
Open Debug ConsoleCtrl + Shift + Y

Last updated: July 2025