How do you debug React applications?

React

The short answer

The main tools are React DevTools (for inspecting components, props, state, and profiling renders), browser DevTools (console, debugger, network tab), and console.log for quick checks. The key is having a systematic approach: reproduce the bug, isolate where it happens, inspect the data, and trace back to the root cause.

React DevTools

React DevTools is a browser extension that adds two tabs: Components and Profiler.

Components tab:

  • Inspect the component tree
  • View and edit props and state of any component
  • See which hooks a component uses and their current values
  • Search for components by name

Profiler tab:

  • Record a session and see which components rendered
  • See how long each render took
  • Find unnecessary re-renders (components that rendered but did not need to)

console.log — still the fastest

For quick debugging, console.log is still the most used tool:

function UserList({ users }) {
console.log('UserList rendered, users:', users);
return (
<ul>
{users.map((user) => {
console.log('Rendering user:', user);
return <li key={user.id}>{user.name}</li>;
})}
</ul>
);
}

Check if the data looks right, if the component is rendering when you expect it to, and if props have the correct values.

Common debugging scenarios

Component not rendering:

  • Check if the component is in the tree (React DevTools Components tab)
  • Check if a conditional is hiding it ({condition && <Component />})
  • Check if the key prop changed unexpectedly (causes remounting)

Stale state or props:

  • Check if you are using the callback form of setState
  • Check useEffect dependencies — missing dependencies cause stale closures
  • Check if you are mutating state instead of creating new objects

Unexpected re-renders:

  • Use React DevTools Profiler to see what triggered the render
  • Check if parent re-renders are causing child re-renders
  • Check if you are creating new objects/functions on every render

Network issues:

  • Use the Network tab to check if requests are being sent
  • Check the response status and body
  • Check if CORS errors are blocking requests

The debugger statement

You can pause execution at any point:

function handleSubmit(data) {
debugger; // execution pauses here when DevTools is open
processData(data);
}

This lets you inspect variables, step through code line by line, and see the call stack.

Error boundaries

For catching rendering errors in production:

class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error('React error:', error, info);
// Send to error tracking service
}
render() {
if (this.state.hasError)
return <p>Something went wrong.</p>;
return this.props.children;
}
}

Interview Tip

Show a systematic approach: reproduce, isolate, inspect, fix. Mention React DevTools (Components and Profiler tabs), console.log for quick checks, and the Network tab for API issues. If you can describe a specific bug you debugged (like a stale closure or unnecessary re-render) and how you found it, that is very compelling.

Why interviewers ask this

Debugging is a daily activity for every developer. Interviewers ask this to see if you have a systematic approach to finding and fixing bugs, if you know the available tools, and if you can debug efficiently. A candidate who can describe their debugging process step by step shows practical experience.