The performance-tuning workflow in 2026 is short: open React DevTools Profiler, record a slow interaction, find the long row, fix it. Then close DevTools and stop. Don't optimize what you haven't measured.
The two-tab workflow
React DevTools has two performance tabs:
- Profiler — records React renders during a window of time. Shows you which components rendered, how long each took, and why (state change, parent re-render, context change).
- Components — inspect any component's current props/state/hooks. Useful for debugging the actual render output, not performance.
What to look for
- Components rendering when they shouldn't — props haven't changed, but the component re-renders anyway. Either a parent context updated, or a non-stable prop (un-memoized callback) is being passed.
- Long render times — one component takes 20ms+. Either expensive computation in render, or rendering too many children. useMemo / virtualization / React.memo + memoized props.
- Cascading re-renders — one state change triggers a tree of renders. Look for state placed too high in the tree (lift it down) or context whose value isn't memoized.
The Suspense indicator
The Profiler shows when a component suspended and how long it took to resolve. Long suspensions visible to the user are the easiest win — either preload the data earlier or split the Suspense boundary.
Concurrent-specific debugging
The 'Why did this render?' field in the Profiler is gold for concurrent React. It tells you whether a render was urgent (state update), transition (low-priority), or initial mount. Mismatches between what you intended (transition) and what happened (urgent) tell you a startTransition wrap is missing.
Don't optimize speculatively. Every memoization, every transition, every memo wrapper adds a tiny cost. If the Profiler shows your app is fast enough, you don't need more optimization — you need to ship the next feature. Performance work pays off when you have a measured problem.