React Developer Tools
React Developer Tools is a browser extension that gives you deep visibility into your running React application. It adds two panels to the browser's DevTools: Components (inspect the live component tree, props, and state) and Profiler (record and analyze renders to find performance bottlenecks). It is an indispensable part of every React developer's workflow.
Installation
Chrome / Edge — search for "React Developer Tools" in the Chrome Web Store, or visit the direct link: chrome.google.com/webstore — click Add to Chrome
Firefox — find it on addons.mozilla.org — click Add to Firefox
Safari — install via the Mac App Store (search "React Developer Tools")
After installation, open any React website (try react.dev) and open DevTools (F12 or right-click → Inspect). You will see two new tabs: Components and Profiler.
The Components Tab
The Components tab shows you the entire React component tree for the current page. Every component you have written — and every component from libraries you use — appears here, nested exactly as they are composed in your code.
What you can see and do:
Component tree — browse the hierarchy. Click any component to select it and see its details in the right panel.
Props — see every prop passed to the selected component, including their current values. Objects and arrays are expandable.
State — see every
useStatecall and its current value. You can edit values directly in the panel to test your UI without changing code.Hooks — all hooks (
useEffect,useContext,useReducer, custom hooks) are listed with their current values.Source — a "Go to source" button takes you to the component's definition in the Sources tab.
Rendered by — shows which parent component rendered the selected component, making it easy to trace the component tree upward.
Search — type a component name in the search bar at the top to jump directly to it. Essential on large pages with deep trees.
Here is a practical example: you have a UserCard component that is not showing the correct name. In DevTools:
Open Components tab and search for "UserCard"
Select the component — look at the props panel on the right
If the
nameprop shows the wrong value, the bug is in the parent (wrong data passed down)If the
nameprop shows the correct value, the bug is in the component's rendering logic
Editing State and Props Live
One of the most powerful features is the ability to edit state values directly in the Components panel without touching your code. Click on any state value in the right panel, edit it, and press Enter. The UI updates immediately.
This is invaluable for testing edge cases: "What does my component look like with an empty array?", "What if the user's name is very long?", "What happens at count = 0?" — test all these without writing test fixtures.
The Profiler Tab
The Profiler tab records rendering activity so you can identify performance problems. Every time a component renders — on mount, on state change, on prop change — the Profiler captures how long it took and why it rendered.
How to use it:
Click the blue circle record button to start recording
Interact with your app — click buttons, type in inputs, navigate between pages
Click the red stop button to end the recording
Examine the resulting flame graph
Flamegraph view — each horizontal bar represents a component. The bar's width represents how long rendering took. Taller stacks mean deeper component trees. Grey bars are components that did not render in that commit; colored bars (yellow/orange/red) rendered and the color indicates relative cost.
Ranked view — sorts all rendered components by render time, slowest first. This makes it trivial to find the most expensive component in a given recording.
Commit selector — at the top of the Profiler, a bar chart shows every "commit" (a batch of DOM updates). Click a commit bar to see the flamegraph for that specific update. Tall bars are slow commits worth investigating.
Why Did This Component Render?
This is the most common performance debugging question. The Profiler shows it directly. Select a component in the flamegraph and look at the right panel — it shows "Why did this render?"
Props changed — a prop's value changed between renders
State changed — the component's own
useStatevalue changedContext changed — a context the component consumes changed
Hooks changed — a custom hook's internal state changed
Parent rendered — the parent re-rendered (which re-renders all children unless they are wrapped in
React.memo)
"Parent rendered" is the most common cause of unnecessary re-renders. When you see a component rendering only because its parent did, and its props did not change, that is a candidate for wrapping in React.memo.
Highlight Updates
In the Components tab, click the settings gear icon (top right). Enable "Highlight updates when components render". Now, whenever a component re-renders, it briefly flashes a colored border:
Blue border — rendered once (on mount or a single update)
Green border — rendered a few times
Yellow/Red border — re-rendering very frequently (potential problem)
Interact with your app while watching for red or yellow flashes. Components that should not be re-rendering (static headers, sidebar items, icon buttons) will stand out immediately.
A Practical Debugging Workflow
When a component is showing wrong data:
Open Components tab, find the component
Check its props — are the values correct? If wrong, the bug is upstream in the parent
Check its state — is the initial value correct? Does it update as expected?
Check hooks — look at
useContextvalues if the component consumes contextEdit a state or prop value in the panel to test how the component responds to the correct value
When the app feels slow:
Open Profiler tab, record while performing the slow interaction
Look for the tallest commit bars
In the flamegraph, look for wide bars (slow renders) and unexpected renders
Check the ranked view to find the most expensive component
Check "Why did this render?" for components that should not be re-rendering
The displayName Property
By default, React DevTools shows component names based on the function name. This works well for named function declarations. It breaks for anonymous functions, higher-order components, or components defined with certain patterns.
// Problem: component shows as "Component" or "Anonymous" in DevTools
const MyComponent = memo(function(props) {
return <div>{props.name}</div>
})
// Solution: set displayName explicitly
const MyComponent = memo(function(props) {
return <div>{props.name}</div>
})
MyComponent.displayName = 'MyComponent'
// Or use a named function inside memo
const MyComponent = memo(function MyComponent(props) {
return <div>{props.name}</div>
})Inspecting Context Values
Context debugging is notoriously difficult without DevTools. With React Developer Tools, select any component that calls useContext — the right panel shows the context value under the Hooks section. You can see exactly what the context provides to that component at that moment, without adding console.log to your code.
// You have this context somewhere
const ThemeContext = createContext('light')
// And this consumer somewhere deep in the tree
function Button({ children }) {
const theme = useContext(ThemeContext)
return <button className={`btn--${theme}`}>{children}</button>
}
// In DevTools: select the Button component
// Under Hooks: Context → value: "light" (or whatever the current value is)
// No console.log required