Chapter 34
Debugging Strategies
Debugging React 19.2 SPAs — React DevTools (Components + Profiler), TanStack Query Devtools, state-store devtools, production source maps, and Sentry / Datadog RUM.
Published 2026-05-23
🎯 Chapter Goal — After this chapter you can drive React DevTools (Components + Profiler), TanStack Query Devtools, Zustand/Jotai/Redux devtools, and the production observability stack (Sentry / Datadog RUM) with the same fluency you have for
console.log.🧭 Prerequisites — Ch 2 (Compiler), Ch 13 (state), Ch 14 (Query).
🔹 34.1 React DevTools — Components and Profiler
The single most useful tool in your debugging toolkit. Install the browser extension; it auto-detects React.
Components tab
- Tree view of the rendered component tree.
- For each component: props, state, hooks, source.
- “Highlight updates when components render” (settings cog) — flashes a border around every component on render. Invaluable for finding render-storm sources.
- ”✨ Memo” badge — Ch 2 §2.1 — confirms the compiler is doing its job.
- Right-click a component → “Find DOM node” — jumps to the rendered element in the Elements panel.
Profiler tab
Covered in Ch 32.1. The key insights:
- Record an interaction; read the flame chart.
- “Ranked” view shows commits ordered by duration.
- Hover any bar — “why did this render?” lists the changed props / state / hooks.
┌─ React DevTools → Profiler ────────────────────────────┐
│ ▶ Record ⏸ ↺ ↤ ↦ Ranked / Flame │
│ │
│ Commit at 1.2 s ████████████████████ 85 ms │
│ <Dashboard> ████████████████ 62 ms │
│ <InvoiceTable> ████████████ 35 ms │
│ (Why? props.invoices changed; identity differs) │
└────────────────────────────────────────────────────────┘
The “Why did this render?” annotation alone saves hours.
🔹 34.2 TanStack Query Devtools
Cross-link Ch 14.5. The panel shows:
- Every active query, keyed by
queryKey. - State: fresh / stale / fetching / inactive.
- Last fetched timestamp.
- Cached data preview.
- Per-query refetch button.
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
<QueryClientProvider client={qc}>
<App />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
Use during development on any non-trivial data-fetching screen. The “why is this still loading?” / “why didn’t this refetch?” questions have visible answers here.
🔹 34.3 Zustand / Jotai / Redux devtools
Zustand — via the devtools middleware
import { devtools } from 'zustand/middleware';
const useStore = create<State>()(devtools((set) => ({ /* … */ }), { name: 'acme' }));
Now your Zustand store shows up in the Redux DevTools extension. Action log, state diff, time-travel.
Jotai — useAtomsDevtools
import { useAtomsDevtools } from 'jotai-devtools';
const AtomsDevtools = () => { useAtomsDevtools('acme'); return null; };
<JotaiProvider><AtomsDevtools /><App /></JotaiProvider>
Atoms appear in Redux DevTools. Slightly less rich than Zustand’s integration but functional.
Redux Toolkit — Redux DevTools out of the box
configureStore enables it by default. Just install the browser extension.
🔹 34.4 Source maps in production (safely)
The dilemma: source maps make production stack traces readable. But they expose your source code to anyone who opens DevTools.
The 2026 standard practice:
- Generate source maps. (
build.sourcemap: 'hidden'in Vite — Ch 17 §17.2.) - Don’t deploy them to the public web.
- Upload them to your error-reporting tool (Sentry / Datadog / Rollbar) — the tool uses them server-side to demangle stack traces.
// vite.config.ts
export default defineConfig({
build: { sourcemap: 'hidden' }, // emits .map files, no // # sourceMappingURL=
});
# CI step
- name: Upload sourcemaps to Sentry
run: |
npx sentry-cli sourcemaps inject ./dist
npx sentry-cli sourcemaps upload ./dist --release "$GIT_SHA"
- name: Remove sourcemaps from deploy
run: rm -f dist/**/*.map
Users see hashed minified code. You see readable stack traces in your error dashboard. Best of both.
🔹 34.5 Sentry / Datadog RUM integration
Sentry
import * as Sentry from '@sentry/react';
Sentry.init({
dsn: env.VITE_SENTRY_DSN,
release: env.VITE_GIT_SHA,
integrations: [
Sentry.browserTracingIntegration(),
Sentry.replayIntegration({ maskAllText: false, maskAllInputs: true }),
],
tracesSampleRate: 0.1, // 10% of transactions
replaysSessionSampleRate: 0.01, // 1% session replay
replaysOnErrorSampleRate: 1.0, // 100% on error
});
// In <App>:
<Sentry.ErrorBoundary fallback={<ErrorPage />}>
<Routes />
</Sentry.ErrorBoundary>
The Replay feature is the killer addition — Sentry records DOM mutations and replays them as video around an error. You see exactly what the user did.
Datadog RUM
import { datadogRum } from '@datadog/browser-rum';
datadogRum.init({
applicationId: env.VITE_DATADOG_APP_ID,
clientToken: env.VITE_DATADOG_TOKEN,
site: 'datadoghq.com',
service: 'acme-web',
env: env.VITE_ENV,
version: env.VITE_GIT_SHA,
sampleRate: 100,
sessionReplaySampleRate: 20,
trackInteractions: true,
});
Pairs naturally with Datadog APM if your backend is also on Datadog — end-to-end traces across the boundary.
Pick one
| Tool | Strengths | Best for |
|---|---|---|
| Sentry | Error-first; replay; SaaS or self-hosted | Teams prioritising error visibility |
| Datadog | Unified frontend + backend; expensive | Teams already on Datadog APM |
| Rollbar | Older; still solid | Legacy installs |
| OpenTelemetry browser SDK | Vendor-agnostic; less polished | Avoiding lock-in |
Don’t run two. The double instrumentation is wasted.
🪤 Common Pitfalls
- Source maps publicly accessible → competitive intel handed out.
- Sentry without releases → stack traces don’t match the right source.
- 100 % sampling → expensive; sample sensibly.
- Replay without input masking → PII leaks into your error tool.
- Forgetting to filter known-noisy errors (browser extensions throwing) → real bugs lost in noise.
- Logging giant objects to console → hangs the dev tools.
✅ Recap
- React DevTools is the most useful tool you’ll use; learn the Profiler.
- TanStack Query Devtools for data; Zustand/Jotai/Redux devtools for state.
- Source maps
hidden+ uploaded to error tool; never deployed publicly. - Pick one observability stack — Sentry default; Datadog if you’re already there.
🔗 Further Reading
- https://react.dev/learn/react-developer-tools — React DevTools docs (React 19.2).
- https://tanstack.com/query/latest/docs/framework/react/devtools — TanStack Query DevTools.
- https://docs.sentry.io/platforms/javascript/guides/react/ — Sentry React SDK docs.
- Ch 14 (Query), Ch 32 (Profiler in perf context), Ch 35 (hard bugs).
In the book — not on the site
Each topic has an 🧠 Under-the-hood subsection — the algorithm, the data structures, what React DevTools surfaces, debugging recipes. Plus a 🧪 hands-on lab per chapter with a starter repo. Reserved for the book.