How to debug React with breakpoints
Breakpoints pause code execution at specific lines, allowing you to inspect variables, call stacks, and application state in real-time. As the creator of CoreUI with 12 years of React development experience, I’ve used breakpoints to debug complex state management issues and performance bottlenecks in production React applications serving millions of users.
The most effective approach combines Chrome DevTools breakpoints with React DevTools for component inspection.
Chrome DevTools Breakpoints
Open Chrome DevTools (F12) and navigate to Sources tab:
function UserProfile({ userId }) {
const [user, setUser] = useState(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
// Click line number to add breakpoint here
fetchUser(userId)
.then(data => {
// Or add breakpoint here
setUser(data)
setLoading(false)
})
.catch(error => {
// Or add breakpoint here
console.error('Error:', error)
setLoading(false)
})
}, [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>
)
}
Click line number in Sources panel to add breakpoint. Execution pauses when that line is reached.
Debugger Statement
function ComplexCalculation({ data }) {
const result = useMemo(() => {
debugger // Execution pauses here
return data.reduce((acc, item) => {
const value = processItem(item)
if (value > threshold) {
debugger // Conditional pause point
return acc + value
}
return acc
}, 0)
}, [data])
return <div>Result: {result}</div>
}
debugger statement pauses execution when DevTools is open.
Conditional Breakpoints
Right-click line number → Add conditional breakpoint:
function ProductList({ products }) {
return (
<ul>
{products.map(product => {
// Right-click line number, add condition: product.price > 100
const discount = calculateDiscount(product)
return (
<li key={product.id}>
{product.name} - ${product.price}
{discount > 0 && <span>Save ${discount}</span>}
</li>
)
})}
</ul>
)
}
Breakpoint only triggers when condition is true.
VS Code Debugging
Create .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Chrome",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}/src",
"sourceMapPathOverrides": {
"webpack:///src/*": "${webRoot}/*"
}
}
]
}
Add breakpoints in VS Code, press F5 to start debugging.
React Component Breakpoints
function Dashboard() {
const [data, setData] = useState([])
useEffect(() => {
debugger // Pause on mount
loadDashboardData().then(result => {
debugger // Pause after data loads
setData(result)
})
}, [])
const handleRefresh = () => {
debugger // Pause on user action
setData([])
loadDashboardData().then(setData)
}
return (
<div>
<button onClick={handleRefresh}>Refresh</button>
<DataTable data={data} />
</div>
)
}
Inspect Variables at Breakpoint
When paused at breakpoint:
function CheckoutForm({ cart }) {
const [coupon, setCoupon] = useState('')
const [discount, setDiscount] = useState(0)
const calculateTotal = () => {
debugger // Pause here
// In DevTools Console, you can now type:
// cart → inspect cart contents
// coupon → see current coupon value
// discount → check discount amount
const subtotal = cart.reduce((sum, item) => sum + item.price, 0)
const total = subtotal - discount
return total
}
return (
<div>
<input
value={coupon}
onChange={(e) => setCoupon(e.target.value)}
/>
<button onClick={calculateTotal}>Calculate</button>
</div>
)
}
Step Through Code
When paused at breakpoint:
- Step Over (F10): Execute current line, move to next
- Step Into (F11): Enter function on current line
- Step Out (Shift+F11): Exit current function
- Continue (F8): Resume execution
function processOrder(order) {
debugger // Pause here
// Press F10 to step over this line
const validated = validateOrder(order)
// Press F11 to step into this function
const price = calculatePrice(order)
// Press Shift+F11 to step out
return submitOrder(order, price)
}
Watch Expressions
Add expressions to watch in DevTools:
function SearchResults({ query, filters }) {
const [results, setResults] = useState([])
useEffect(() => {
debugger
// Add to Watch:
// query.length
// filters.category
// results.length
searchAPI(query, filters).then(setResults)
}, [query, filters])
return (
<ul>
{results.map(item => (
<li key={item.id}>{item.title}</li>
))}
</ul>
)
}
Call Stack Inspection
function Parent() {
const handleClick = () => {
debugger // Pause here to see call stack
processAction()
}
return <Child onClick={handleClick} />
}
function Child({ onClick }) {
return <button onClick={onClick}>Click</button>
}
function processAction() {
debugger // Call stack shows: processAction → handleClick → onClick
console.log('Action processed')
}
Call stack shows function call hierarchy.
Best Practice Note
This is the debugging workflow we use across all CoreUI React projects. Breakpoints are more powerful than console.log because they pause execution and allow full state inspection. Use conditional breakpoints for loops and frequently called functions, and combine DevTools breakpoints with React DevTools to inspect component props and state simultaneously.
For production applications, consider using CoreUI’s React Admin Template which includes pre-configured debugging setup for development environments.
Related Articles
For more debugging techniques, check out how to use React DevTools and how to debug React hooks.



