React Developer Tools
Learn to use React Developer Tools for debugging and understanding React applications. This is a foundational concept in component-based UI development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world React experience. Take your time with each section and practice the examples
Installing React Developer Tools
React Developer Tools is a browser extension that helps you inspect React components, view their props and state, and understand the component hierarchy. It's an essential tool for React development.. This is an essential concept that every React developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
Browser Extensions
- Chrome: Install from Chrome Web Store
- Firefox: Install from Firefox Add-ons
- Edge: Install from Microsoft Edge Add-ons
- Safari: Install from Safari Extensions Gallery
Using React Developer Tools
// After installing the extension, you'll see a new tab in your browser's developer tools
// 1. Components Tab
// - View component hierarchy
// - Inspect component props and state
// - See component names and file locations
// - Highlight components on the page
// 2. Profiler Tab
// - Record performance profiles
// - Analyze component render times
// - Identify performance bottlenecks
// - Optimize component rendering
// Example component to inspect
function UserProfile({ user, onUpdate }) {
const [isEditing, setIsEditing] = useState(false);
const [formData, setFormData] = useState(user);
const handleSubmit = (e) => {
e.preventDefault();
onUpdate(formData);
setIsEditing(false);
};
return (
<div className="user-profile">
{isEditing ? (
<form onSubmit={handleSubmit}>
<input
value={formData.name}
onChange={(e) => setFormData({
...formData,
name: e.target.value
})}
/>
<input
value={formData.email}
onChange={(e) => setFormData({
...formData,
email: e.target.value
})}
/>
<button type="submit">Save</button>
<button type="button" onClick={() => setIsEditing(false)}>
Cancel
</button>
</form>
) : (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
<button onClick={() => setIsEditing(true)}>Edit</button>
</div>
)}
</div>
);
}
// In React DevTools, you can:
// - See the component tree
// - Inspect props and state values
// - Modify state in real-time
// - See component render times
// - Identify unnecessary re-rendersDebugging with React DevTools
// Common debugging scenarios
// 1. Props not updating
function ParentComponent() {
const [user, setUser] = useState({ name: 'John', email: 'john@example.com' });
// Check in DevTools if props are being passed correctly
return <UserProfile user={user} onUpdate={setUser} />;
}
// 2. State not updating
function Counter() {
const [count, setCount] = useState(0);
// Use DevTools to see if state is actually changing
const increment = () => {
setCount(prev => prev + 1);
console.log('Count should be:', count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
// 3. Component not re-rendering
function ExpensiveComponent({ data }) {
// Use Profiler to see if component is re-rendering unnecessarily
console.log('ExpensiveComponent rendered');
return (
<div>
{data.map(item => (
<div key={item.id}>{item.name}</div>
))}
</div>
);
}
// 4. Performance optimization
function OptimizedComponent({ items }) {
// Use Profiler to measure render performance
const memoizedItems = useMemo(() => {
return items.filter(item => item.active);
}, [items]);
return (
<div>
{memoizedItems.map(item => (
<div key={item.id}>{item.name}</div>
))}
</div>
);
}Practice Exercise: Debugging
// Exercise: Debug a React Application
// Create a buggy component and use DevTools to fix it
// src/components/BuggyCounter.js
import React, { useState, useEffect } from 'react';
function BuggyCounter() {
const [count, setCount] = useState(0);
const [isRunning, setIsRunning] = useState(false);
// Bug: useEffect dependency array is missing
useEffect(() => {
let interval;
if (isRunning) {
interval = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
}
return () => clearInterval(interval);
}); // Missing dependency array!
return (
<div className="buggy-counter">
<h2>Count: {count}</h2>
<button onClick={() => setIsRunning(!isRunning)}>
{isRunning ? 'Stop' : 'Start'}
</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
// src/components/BuggyUserList.js
function BuggyUserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Simulate API call
setTimeout(() => {
setUsers([
{ id: 1, name: 'John', email: 'john@example.com' },
{ id: 2, name: 'Jane', email: 'jane@example.com' },
{ id: 3, name: 'Bob', email: 'bob@example.com' }
]);
setLoading(false);
}, 2000);
}, []);
const deleteUser = (id) => {
// Bug: Not updating state correctly
users.filter(user => user.id !== id);
// Should be: setUsers(users.filter(user => user.id !== id));
};
if (loading) {
return <div>Loading...</div>;
}
return (
<div className="user-list">
<h2>Users</h2>
{users.map(user => (
<div key={user.id} className="user-item">
<span>{user.name}</span>
<span>{user.email}</span>
<button onClick={() => deleteUser(user.id)}>Delete</button>
</div>
))}
</div>
);
}
// Tasks:
// 1. Install React Developer Tools
// 2. Open the application in browser
// 3. Open DevTools and go to React tab
// 4. Identify the bugs using component inspection
// 5. Fix the bugs and verify in DevTools
// 6. Use Profiler to check performance
// Expected bugs to find:
// - useEffect missing dependency array
// - State not updating correctly
// - Unnecessary re-renders
// - Missing key props