@nhonh/react-debugger 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,960 @@
1
+ # React Debugger - Complete Tabs Guide
2
+
3
+ Deep dive into each tab's features, metrics, and how to use them effectively.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Timeline Tab](#1-timeline-tab)
10
+ 2. [UI & State Tab](#2-ui--state-tab)
11
+ 3. [Performance Tab](#3-performance-tab)
12
+ 4. [Memory Tab](#4-memory-tab)
13
+ 5. [Side Effects Tab](#5-side-effects-tab)
14
+ 6. [CLS Tab](#6-cls-tab)
15
+ 7. [Redux Tab](#7-redux-tab)
16
+
17
+ ---
18
+
19
+ ## 1. Timeline Tab
20
+
21
+ The Timeline provides a chronological view of everything happening in your React app.
22
+
23
+ ### Event Types
24
+
25
+ | Icon | Type | Description |
26
+ |------|------|-------------|
27
+ | 🔄 | **Render** | Component render/re-render |
28
+ | 📦 | **State** | State change (local or Redux) |
29
+ | ⚡ | **Effect** | useEffect execution |
30
+ | ❌ | **Error** | JavaScript error |
31
+ | 🧠 | **Memory** | Memory snapshot |
32
+ | 🔗 | **Context** | Context value change |
33
+
34
+ ### Render Events
35
+
36
+ Each render event shows:
37
+
38
+ ```
39
+ ┌─────────────────────────────────────────────────┐
40
+ │ 🔄 MyComponent 12:34:56 │
41
+ │ ─────────────────────────────────────────────── │
42
+ │ Duration: 2.3ms │
43
+ │ Trigger: props (items, onClick) │
44
+ │ Fiber Depth: 5 │
45
+ │ Render Order: #3 in batch │
46
+ └─────────────────────────────────────────────────┘
47
+ ```
48
+
49
+ | Field | Meaning |
50
+ |-------|---------|
51
+ | Duration | How long the render took |
52
+ | Trigger | What caused the render |
53
+ | Fiber Depth | Component depth in tree |
54
+ | Render Order | Position in render batch |
55
+
56
+ ### State Change Events
57
+
58
+ ```
59
+ ┌─────────────────────────────────────────────────┐
60
+ │ 📦 State Change 12:34:57 │
61
+ │ ─────────────────────────────────────────────── │
62
+ │ Component: Counter │
63
+ │ Hook: useState (#0) │
64
+ │ State Name: count │
65
+ │ Old Value: 5 │
66
+ │ New Value: 6 │
67
+ └─────────────────────────────────────────────────┘
68
+ ```
69
+
70
+ ### Using Filters
71
+
72
+ Click filter buttons to show/hide event types:
73
+
74
+ ```
75
+ [🔄 Renders ✓] [📦 State ✓] [⚡ Effects] [❌ Errors ✓]
76
+ ```
77
+
78
+ ### Search
79
+
80
+ Type in the search box to filter by:
81
+ - Component name
82
+ - Event type
83
+ - Action type (for Redux)
84
+
85
+ ### Event Correlation
86
+
87
+ Click any event to highlight related events:
88
+ - Renders that followed a state change
89
+ - Effects triggered by renders
90
+ - Errors with their causes
91
+
92
+ ---
93
+
94
+ ## 2. UI & State Tab
95
+
96
+ Automatically detects React anti-patterns and common mistakes.
97
+
98
+ ### Issue Types
99
+
100
+ #### 🔴 DIRECT_STATE_MUTATION (Error)
101
+
102
+ **Problem:** Modifying state object directly instead of creating new reference.
103
+
104
+ ```jsx
105
+ // ❌ Bad - React won't detect the change
106
+ const [user, setUser] = useState({ name: 'John' });
107
+ user.name = 'Jane'; // Direct mutation!
108
+ setUser(user);
109
+
110
+ // ✅ Good - Create new object
111
+ setUser({ ...user, name: 'Jane' });
112
+ ```
113
+
114
+ **Why it matters:** React uses reference equality to detect changes. Mutating the same object doesn't trigger re-renders.
115
+
116
+ ---
117
+
118
+ #### 🟡 MISSING_KEY (Warning)
119
+
120
+ **Problem:** List items rendered without `key` prop.
121
+
122
+ ```jsx
123
+ // ❌ Bad
124
+ {items.map(item => <li>{item}</li>)}
125
+
126
+ // ✅ Good
127
+ {items.map(item => <li key={item.id}>{item}</li>)}
128
+ ```
129
+
130
+ **Why it matters:** Without keys, React can't track which items changed, leading to bugs and poor performance.
131
+
132
+ ---
133
+
134
+ #### 🟡 INDEX_AS_KEY (Warning)
135
+
136
+ **Problem:** Using array index as key for dynamic lists.
137
+
138
+ ```jsx
139
+ // ❌ Bad - problematic when list order changes
140
+ {items.map((item, index) => <li key={index}>{item}</li>)}
141
+
142
+ // ✅ Good - use stable unique ID
143
+ {items.map(item => <li key={item.id}>{item}</li>)}
144
+ ```
145
+
146
+ **When index IS okay:**
147
+ - Static lists that never change
148
+ - No reordering, adding, or removing items
149
+ - Items have no state
150
+
151
+ ---
152
+
153
+ #### 🔴 DUPLICATE_KEY (Error)
154
+
155
+ **Problem:** Multiple items have the same key.
156
+
157
+ ```jsx
158
+ // ❌ Bad - two items with key="1"
159
+ <li key="1">Apple</li>
160
+ <li key="1">Banana</li> // Duplicate!
161
+
162
+ // ✅ Good - unique keys
163
+ <li key="apple">Apple</li>
164
+ <li key="banana">Banana</li>
165
+ ```
166
+
167
+ ---
168
+
169
+ ### Issue Card Anatomy
170
+
171
+ ```
172
+ ┌─────────────────────────────────────────────────┐
173
+ │ 🔴 DIRECT_STATE_MUTATION │
174
+ │ ─────────────────────────────────────────────── │
175
+ │ Component: UserProfile │
176
+ │ Path: App > Dashboard > UserProfile │
177
+ │ │
178
+ │ Message: State object was mutated directly │
179
+ │ │
180
+ │ 💡 Suggestion: Create a new object/array │
181
+ │ instead of modifying the existing one. │
182
+ │ │
183
+ │ [View Code] [Dismiss] │
184
+ └─────────────────────────────────────────────────┘
185
+ ```
186
+
187
+ ---
188
+
189
+ ## 3. Performance Tab
190
+
191
+ Comprehensive performance analysis with Core Web Vitals and render statistics.
192
+
193
+ ### Statistics Dashboard
194
+
195
+ ```
196
+ ┌──────────────┬──────────────┬──────────────┬──────────────┐
197
+ │ Components │ Total Renders│ Avg Render │ Slow Renders │
198
+ │ 24 │ 156 │ 4.2ms │ 3 │
199
+ └──────────────┴──────────────┴──────────────┴──────────────┘
200
+ ```
201
+
202
+ | Metric | Description | Target |
203
+ |--------|-------------|--------|
204
+ | Components | Tracked components | - |
205
+ | Total Renders | Sum of all renders | Lower = better |
206
+ | Avg Render | Average render time | < 16ms |
207
+ | Slow Renders | Renders > 16ms | 0 |
208
+
209
+ ### Core Web Vitals
210
+
211
+ ```
212
+ ┌────────────────────────────────────────────────────────┐
213
+ │ Page Load Metrics │
214
+ │ ────────────────────────────────────────────────────── │
215
+ │ FCP: 1.2s ✅ LCP: 2.1s ✅ TTFB: 0.3s ✅ │
216
+ └────────────────────────────────────────────────────────┘
217
+ ```
218
+
219
+ | Metric | Full Name | Good | Needs Work | Poor |
220
+ |--------|-----------|------|------------|------|
221
+ | FCP | First Contentful Paint | < 1.8s | 1.8-3s | > 3s |
222
+ | LCP | Largest Contentful Paint | < 2.5s | 2.5-4s | > 4s |
223
+ | TTFB | Time to First Byte | < 0.8s | 0.8-1.8s | > 1.8s |
224
+
225
+ ### Slowest Components Table
226
+
227
+ ```
228
+ ┌─────────────────┬──────────┬──────────┬─────────┐
229
+ │ Component │ Max Time │ Avg Time │ Renders │
230
+ ├─────────────────┼──────────┼──────────┼─────────┤
231
+ │ DataGrid │ 45.2ms │ 23.1ms │ 12 │
232
+ │ Chart │ 32.1ms │ 18.5ms │ 8 │
233
+ │ UserList │ 28.7ms │ 15.2ms │ 24 │
234
+ └─────────────────┴──────────┴──────────┴─────────┘
235
+ ```
236
+
237
+ **Action:** Focus on components with Max Time > 16ms.
238
+
239
+ ### Top Re-rendering Components
240
+
241
+ ```
242
+ ┌─────────────────┬─────────┬──────────┬───────────┬─────────────┐
243
+ │ Component │ Renders │ Avg Time │ Self Time │ Last Trigger│
244
+ ├─────────────────┼─────────┼──────────┼───────────┼─────────────┤
245
+ │ SearchInput │ 47 │ 1.2ms │ 0.8ms │ state │
246
+ │ FilterButton │ 32 │ 0.5ms │ 0.3ms │ parent │
247
+ │ ListItem │ 28 │ 0.3ms │ 0.2ms │ props │
248
+ └─────────────────┴─────────┴──────────┴───────────┴─────────────┘
249
+ ```
250
+
251
+ | Column | Meaning |
252
+ |--------|---------|
253
+ | Renders | Total render count |
254
+ | Avg Time | Average total render time |
255
+ | Self Time | Time in component (excluding children) |
256
+ | Last Trigger | Most recent render cause |
257
+
258
+ ### React Scan (Visual Mode)
259
+
260
+ Toggle ON to see renders directly on the page:
261
+
262
+ | Color | Render Count | Meaning |
263
+ |-------|--------------|---------|
264
+ | 🟢 Green | 1 | Initial mount |
265
+ | 🟡 Yellow | 2-3 | Some re-renders |
266
+ | 🟠 Orange | 4-5 | Frequent re-renders |
267
+ | 🔴 Red | 10+ | Excessive - optimize! |
268
+
269
+ ### Optimization Strategies
270
+
271
+ **For `props` trigger:**
272
+ ```jsx
273
+ // Wrap with React.memo
274
+ export const MyComponent = React.memo(({ data }) => {
275
+ return <div>{data.name}</div>;
276
+ });
277
+ ```
278
+
279
+ **For `parent` trigger:**
280
+ ```jsx
281
+ // Memoize to prevent re-render when parent updates
282
+ export const Child = React.memo(({ value }) => {
283
+ return <span>{value}</span>;
284
+ });
285
+ ```
286
+
287
+ **For `state` trigger:**
288
+ ```jsx
289
+ // Batch state updates
290
+ const handleClick = () => {
291
+ // React 18+ auto-batches, but be mindful
292
+ setCount(c => c + 1);
293
+ setFlag(f => !f);
294
+ };
295
+ ```
296
+
297
+ **For `context` trigger:**
298
+ ```jsx
299
+ // Split contexts by update frequency
300
+ const ThemeContext = createContext(); // Rarely changes
301
+ const UserContext = createContext(); // Changes on login
302
+ ```
303
+
304
+ ---
305
+
306
+ ## 4. Memory Tab
307
+
308
+ Monitor JavaScript heap usage and detect memory leaks.
309
+
310
+ ### Dashboard
311
+
312
+ ```
313
+ ┌────────────────────────────────────────────────────────┐
314
+ │ Memory Usage │
315
+ │ ════════════════════════════════════════════════════ │
316
+ │ ████████████████████░░░░░░░░░░░░ 65% │
317
+ │ │
318
+ │ Used: 45.2 MB Total: 69.5 MB Limit: 4.0 GB │
319
+ │ Peak: 52.1 MB Growth: +12 KB/s │
320
+ └────────────────────────────────────────────────────────┘
321
+ ```
322
+
323
+ ### Key Metrics
324
+
325
+ | Metric | Description |
326
+ |--------|-------------|
327
+ | Used Heap | Currently allocated memory |
328
+ | Total Heap | Memory available to JS engine |
329
+ | Heap Limit | Maximum allowed |
330
+ | Peak Usage | Highest recorded usage |
331
+ | Growth Rate | Memory change per second |
332
+
333
+ ### Health Indicators
334
+
335
+ | Usage | Status | Action |
336
+ |-------|--------|--------|
337
+ | < 70% | ✅ Healthy | No action |
338
+ | 70-90% | ⚠️ Warning | Monitor |
339
+ | > 90% | 🔴 Critical | Investigate |
340
+
341
+ ### Growth Rate Analysis
342
+
343
+ | Rate | Status | Meaning |
344
+ |------|--------|---------|
345
+ | Negative | ✅ Good | GC is working |
346
+ | 0 - 512 KB/s | ✅ Normal | Typical fluctuation |
347
+ | 512 KB - 1 MB/s | ⚠️ Warning | Possible leak |
348
+ | > 1 MB/s | 🔴 Critical | Likely memory leak |
349
+
350
+ ### Memory Chart
351
+
352
+ The chart shows memory usage over time:
353
+ - **Blue line:** Used heap
354
+ - **Gray line:** Total heap
355
+ - **Spikes:** Indicate allocations
356
+ - **Drops:** Indicate garbage collection
357
+
358
+ ### Crash Log
359
+
360
+ Captures errors with memory context:
361
+
362
+ ```
363
+ ┌─────────────────────────────────────────────────────┐
364
+ │ ❌ TypeError 12:34:56 │
365
+ │ ─────────────────────────────────────────────────── │
366
+ │ Cannot read property 'map' of undefined │
367
+ │ │
368
+ │ Component Stack: │
369
+ │ at UserList (UserList.jsx:15) │
370
+ │ at Dashboard (Dashboard.jsx:42) │
371
+ │ │
372
+ │ Memory at crash: 67.2 MB (78%) │
373
+ └─────────────────────────────────────────────────────┘
374
+ ```
375
+
376
+ ### Finding Memory Leaks
377
+
378
+ 1. **Start Monitoring** - Click the button
379
+ 2. **Create a baseline** - Note initial memory
380
+ 3. **Perform actions** - Navigate, open/close modals
381
+ 4. **Return to start** - Go back to initial state
382
+ 5. **Compare** - Memory should return to baseline
383
+
384
+ **Common leak sources:**
385
+ - Event listeners not removed
386
+ - Timers not cleared
387
+ - Subscriptions not unsubscribed
388
+ - Closures holding references
389
+
390
+ ---
391
+
392
+ ## 5. Side Effects Tab
393
+
394
+ Analyze useEffect hooks for common issues.
395
+
396
+ ### Issue Categories
397
+
398
+ #### MISSING_CLEANUP
399
+
400
+ ```jsx
401
+ // ❌ Bad - timer keeps running after unmount
402
+ useEffect(() => {
403
+ const id = setInterval(() => {
404
+ console.log('tick');
405
+ }, 1000);
406
+ // Missing cleanup!
407
+ }, []);
408
+
409
+ // ✅ Good
410
+ useEffect(() => {
411
+ const id = setInterval(() => {
412
+ console.log('tick');
413
+ }, 1000);
414
+ return () => clearInterval(id); // Cleanup
415
+ }, []);
416
+ ```
417
+
418
+ #### MISSING_DEP
419
+
420
+ ```jsx
421
+ // ❌ Bad - count not in dependencies
422
+ useEffect(() => {
423
+ document.title = `Count: ${count}`;
424
+ }, []); // Should be [count]
425
+
426
+ // ✅ Good
427
+ useEffect(() => {
428
+ document.title = `Count: ${count}`;
429
+ }, [count]);
430
+ ```
431
+
432
+ #### INFINITE_LOOP_RISK
433
+
434
+ ```jsx
435
+ // ❌ Bad - updates state that triggers effect again
436
+ useEffect(() => {
437
+ setCount(count + 1); // Infinite loop!
438
+ }, [count]);
439
+
440
+ // ✅ Good - use functional update
441
+ useEffect(() => {
442
+ setCount(c => c + 1);
443
+ }, []); // Run once
444
+ ```
445
+
446
+ #### STALE_CLOSURE
447
+
448
+ ```jsx
449
+ // ❌ Bad - callback captures stale count value
450
+ useEffect(() => {
451
+ const handler = () => {
452
+ console.log(count); // Always logs initial value
453
+ };
454
+ window.addEventListener('click', handler);
455
+ return () => window.removeEventListener('click', handler);
456
+ }, []); // Missing count
457
+
458
+ // ✅ Good - use ref for latest value
459
+ const countRef = useRef(count);
460
+ countRef.current = count;
461
+
462
+ useEffect(() => {
463
+ const handler = () => {
464
+ console.log(countRef.current); // Always current
465
+ };
466
+ window.addEventListener('click', handler);
467
+ return () => window.removeEventListener('click', handler);
468
+ }, []);
469
+ ```
470
+
471
+ ### Effect Card Details
472
+
473
+ ```
474
+ ┌─────────────────────────────────────────────────────┐
475
+ │ ⚠️ MISSING_CLEANUP │
476
+ │ ─────────────────────────────────────────────────── │
477
+ │ Component: DataFetcher │
478
+ │ Effect Index: #0 │
479
+ │ │
480
+ │ Dependencies: [userId] │
481
+ │ Has Cleanup: No ❌ │
482
+ │ │
483
+ │ Effect Preview: │
484
+ │ fetch(`/api/user/${userId}`) │
485
+ │ .then(res => setUser(res)) │
486
+ │ │
487
+ │ 💡 Tip: Use AbortController for fetch cleanup │
488
+ └─────────────────────────────────────────────────────┘
489
+ ```
490
+
491
+ ---
492
+
493
+ ## 6. CLS Tab
494
+
495
+ Monitor Cumulative Layout Shift - a Core Web Vital for visual stability.
496
+
497
+ ### Score Interpretation
498
+
499
+ | Score | Rating | User Experience |
500
+ |-------|--------|-----------------|
501
+ | < 0.1 | ✅ Good | Stable, smooth |
502
+ | 0.1 - 0.25 | ⚠️ Needs Improvement | Noticeable shifts |
503
+ | > 0.25 | 🔴 Poor | Frustrating experience |
504
+
505
+ ### Dashboard
506
+
507
+ ```
508
+ ┌────────────────────────────────────────────────────────┐
509
+ │ CLS Score: 0.15 │
510
+ │ ████████████████░░░░░░░░░░░░░░ ⚠️ Needs Improvement │
511
+ │ │
512
+ │ Total Shifts: 5 Last Shift: 2.3s ago │
513
+ └────────────────────────────────────────────────────────┘
514
+ ```
515
+
516
+ ### Top Shift Sources
517
+
518
+ ```
519
+ ┌─────────────────────────────────┬────────────┬────────────┐
520
+ │ Element │ Total Shift│ Occurrences│
521
+ ├─────────────────────────────────┼────────────┼────────────┤
522
+ │ img.hero-image │ 0.08 │ 1 │
523
+ │ div.ad-container │ 0.05 │ 3 │
524
+ │ p.dynamic-content │ 0.02 │ 2 │
525
+ └─────────────────────────────────┴────────────┴────────────┘
526
+ ```
527
+
528
+ ### Common Causes & Fixes
529
+
530
+ | Cause | Fix |
531
+ |-------|-----|
532
+ | Images without dimensions | Add `width` and `height` attributes |
533
+ | Ads/embeds | Set explicit container dimensions |
534
+ | Dynamic content | Reserve space with `min-height` |
535
+ | Web fonts | Use `font-display: swap` |
536
+ | Animations | Use `transform` instead of `top/left` |
537
+
538
+ **Image fix:**
539
+ ```jsx
540
+ // ❌ Bad
541
+ <img src="photo.jpg" alt="Photo" />
542
+
543
+ // ✅ Good
544
+ <img src="photo.jpg" alt="Photo" width={800} height={600} />
545
+
546
+ // ✅ Also good - aspect ratio
547
+ <img
548
+ src="photo.jpg"
549
+ alt="Photo"
550
+ style={{ aspectRatio: '16/9', width: '100%' }}
551
+ />
552
+ ```
553
+
554
+ **Dynamic content fix:**
555
+ ```jsx
556
+ // ❌ Bad - content pushes things down
557
+ {loaded && <Content />}
558
+
559
+ // ✅ Good - space reserved
560
+ <div style={{ minHeight: 200 }}>
561
+ {loaded ? <Content /> : <Skeleton />}
562
+ </div>
563
+ ```
564
+
565
+ ---
566
+
567
+ ## 7. Redux Tab
568
+
569
+ **The most powerful Redux debugging experience** - view state, edit values live, dispatch actions, and manipulate arrays directly.
570
+
571
+ ### Overview
572
+
573
+ ```
574
+ ┌─────────────────────────────────────────────────────────────────┐
575
+ │ 🗄️ Redux DevTools [🔄] │
576
+ ├────────────────────────┬────────────────────────────────────────┤
577
+ │ Action History (12) │ State Tree [🔍] [+] [−] [⟲]│
578
+ │ ───────────────────────│────────────────────────────────────────│
579
+ │ 12:34:56 user/login │ ▼ user │
580
+ │ 12:34:58 posts/fetch │ ├─ id: 123 ← click to edit │
581
+ │ 12:35:01 ui/toggle │ ├─ name: "John" ← click to edit │
582
+ │ 12:35:03 cart/add ◀── │ └─ role: "admin" │
583
+ │ │ ▼ cart │
584
+ │ [Action Details] │ └─ items: Array(3) [↑] [↓] [×] │
585
+ └────────────────────────┴────────────────────────────────────────┘
586
+ │ Dispatch Action │
587
+ │ Type: [cart/addItem ] Payload: [{ "id": 4 }] [Send] │
588
+ └─────────────────────────────────────────────────────────────────┘
589
+ ```
590
+
591
+ ---
592
+
593
+ ### 🌳 State Tree Browser
594
+
595
+ Interactive tree view of your entire Redux state.
596
+
597
+ ```
598
+ ┌─────────────────────────────────────────────────────┐
599
+ │ 🔍 Search state... [+] [−] [⟲] │
600
+ ├─────────────────────────────────────────────────────┤
601
+ │ ▼ user │
602
+ │ ├─ id: 123 ← Number (editable)│
603
+ │ ├─ name: "John Doe" ← String (editable)│
604
+ │ ├─ isAdmin: true ← Boolean (toggle) │
605
+ │ └─ email: "john@example.com" │
606
+ │ ▼ cart │
607
+ │ ├─ total: 99.99 │
608
+ │ └▼ items: Array(2) │
609
+ │ ├─ [0]: { id: 1, name: "Book" } [↑][↓][×] │
610
+ │ └─ [1]: { id: 2, name: "Pen" } [↑][↓][×] │
611
+ │ ▶ settings (collapsed - click to expand) │
612
+ └─────────────────────────────────────────────────────┘
613
+ ```
614
+
615
+ #### Controls
616
+
617
+ | Button | Action |
618
+ |--------|--------|
619
+ | `+` | Expand all nodes |
620
+ | `−` | Collapse all nodes |
621
+ | `⟲` | Reset all edited values |
622
+ | `🔄` | Refresh state from store |
623
+
624
+ #### Search
625
+
626
+ Type in the search box to filter state keys:
627
+ - Searches both key names and values
628
+ - Great for finding specific data in large state trees
629
+
630
+ ---
631
+
632
+ ### ✏️ Live State Editing (Key Feature!)
633
+
634
+ **Click any value to edit it directly** - changes apply immediately via Redux.
635
+
636
+ #### Supported Types
637
+
638
+ | Type | How to Edit |
639
+ |------|-------------|
640
+ | **String** | Click → Type new value → Enter |
641
+ | **Number** | Click → Type number → Enter |
642
+ | **Boolean** | Click → Dropdown (true/false) |
643
+ | **Object/Array** | Click → JSON editor → Enter |
644
+ | **null** | Click → Edit as any type |
645
+
646
+ #### Editing Workflow
647
+
648
+ ```
649
+ 1. Click on a value:
650
+ name: "John" → name: [John ] [✓] [✗]
651
+ ↑ editable input
652
+
653
+ 2. Modify the value:
654
+ name: [Jane ] [✓] [✗]
655
+
656
+ 3. Press Enter or click ✓ to save
657
+ Changes apply immediately to Redux store!
658
+
659
+ 4. Press Escape or click ✗ to cancel
660
+ ```
661
+
662
+ #### Keyboard Shortcuts
663
+
664
+ | Key | Action |
665
+ |-----|--------|
666
+ | `Enter` | Save changes |
667
+ | `Escape` | Cancel editing |
668
+
669
+ #### Example Use Cases
670
+
671
+ ```jsx
672
+ // Testing different user roles
673
+ user.role: "admin" → "moderator" → "user"
674
+
675
+ // Adjusting cart totals
676
+ cart.total: 99.99 → 0 → 150.00
677
+
678
+ // Toggling feature flags
679
+ features.darkMode: false → true
680
+
681
+ // Modifying complex objects
682
+ user.preferences: { theme: "light" } → { theme: "dark", fontSize: 16 }
683
+ ```
684
+
685
+ ---
686
+
687
+ ### 📦 Array Manipulation
688
+
689
+ **Powerful array controls** for each item in arrays:
690
+
691
+ ```
692
+ ▼ cart.items: Array(3)
693
+ ├─ [0]: { id: 1, name: "Book" } [↑] [↓] [×]
694
+ ├─ [1]: { id: 2, name: "Pen" } [↑] [↓] [×]
695
+ └─ [2]: { id: 3, name: "Paper" } [↑] [↓] [×]
696
+ ```
697
+
698
+ | Button | Action | Use Case |
699
+ |--------|--------|----------|
700
+ | `↑` | Move item up | Reorder list items |
701
+ | `↓` | Move item down | Reorder list items |
702
+ | `×` | Delete item | Remove from array |
703
+
704
+ #### Example: Reordering Cart Items
705
+
706
+ ```
707
+ Before: After clicking ↑ on [1]:
708
+ ├─ [0]: Book ├─ [0]: Pen ← moved up
709
+ ├─ [1]: Pen ├─ [1]: Book ← moved down
710
+ └─ [2]: Paper └─ [2]: Paper
711
+ ```
712
+
713
+ ---
714
+
715
+ ### 📜 Action History
716
+
717
+ See every Redux action dispatched in your app:
718
+
719
+ ```
720
+ ┌─────────────────────────────────────────────────────┐
721
+ │ Action History (47) │
722
+ ├─────────────────────────────────────────────────────┤
723
+ │ 12:34:56 user/login │
724
+ │ 12:34:58 posts/fetchPending │
725
+ │ 12:35:01 posts/fetchSuccess │
726
+ │ 12:35:03 cart/addItem ← Click to select │
727
+ │ 12:35:05 ui/openModal │
728
+ └─────────────────────────────────────────────────────┘
729
+ ```
730
+
731
+ #### Click an Action to See Details
732
+
733
+ ```
734
+ ┌─────────────────────────────────────────────────────┐
735
+ │ Action: cart/addItem │
736
+ ├─────────────────────────────────────────────────────┤
737
+ │ Payload: │
738
+ │ { │
739
+ │ "productId": 123, │
740
+ │ "quantity": 2, │
741
+ │ "price": 29.99 │
742
+ │ } │
743
+ └─────────────────────────────────────────────────────┘
744
+ ```
745
+
746
+ **Use cases:**
747
+ - Debug why state changed unexpectedly
748
+ - Verify actions are dispatched correctly
749
+ - Check action payloads for errors
750
+
751
+ ---
752
+
753
+ ### 🚀 Action Dispatcher
754
+
755
+ **Test your reducers** by dispatching custom actions:
756
+
757
+ ```
758
+ ┌─────────────────────────────────────────────────────┐
759
+ │ Dispatch Action │
760
+ ├─────────────────────────────────────────────────────┤
761
+ │ Type: │
762
+ │ [cart/addItem ] │
763
+ │ │
764
+ │ Payload (JSON): │
765
+ │ [ ] │
766
+ │ [{ ] │
767
+ │ [ "productId": 999, ] │
768
+ │ [ "quantity": 1 ] │
769
+ │ [} ] │
770
+ │ │
771
+ │ [Dispatch Action] │
772
+ └─────────────────────────────────────────────────────┘
773
+ ```
774
+
775
+ #### Common Testing Scenarios
776
+
777
+ **Test edge cases:**
778
+ ```json
779
+ // Empty cart
780
+ Type: cart/clear
781
+ Payload: {}
782
+
783
+ // Add item with invalid data
784
+ Type: cart/addItem
785
+ Payload: { "productId": null, "quantity": -1 }
786
+
787
+ // Simulate API error
788
+ Type: api/error
789
+ Payload: { "code": 500, "message": "Server error" }
790
+ ```
791
+
792
+ **Test user flows:**
793
+ ```json
794
+ // Login as different user
795
+ Type: auth/loginSuccess
796
+ Payload: { "userId": 456, "role": "admin" }
797
+
798
+ // Toggle feature flag
799
+ Type: features/toggle
800
+ Payload: { "feature": "darkMode", "enabled": true }
801
+ ```
802
+
803
+ ---
804
+
805
+ ### 🔍 Redux Detection Methods
806
+
807
+ The extension automatically finds your Redux store via:
808
+
809
+ | Method | Priority | Description |
810
+ |--------|----------|-------------|
811
+ | `window.store` | 1st | Explicitly exposed store |
812
+ | `window.__REDUX_STORE__` | 2nd | Alternative naming |
813
+ | Redux DevTools Extension | 3rd | Uses existing connection |
814
+ | React-Redux Provider | 4th | Finds store in React fiber tree |
815
+
816
+ #### Recommended Setup
817
+
818
+ ```jsx
819
+ // store.js
820
+ import { configureStore } from '@reduxjs/toolkit';
821
+ import rootReducer from './reducers';
822
+
823
+ const store = configureStore({
824
+ reducer: rootReducer,
825
+ devTools: process.env.NODE_ENV !== 'production',
826
+ });
827
+
828
+ // Expose for React Debugger (development only)
829
+ if (process.env.NODE_ENV === 'development') {
830
+ window.store = store;
831
+ }
832
+
833
+ export default store;
834
+ ```
835
+
836
+ #### Redux Toolkit (Recommended)
837
+
838
+ ```jsx
839
+ // RTK automatically connects to DevTools
840
+ import { configureStore } from '@reduxjs/toolkit';
841
+
842
+ const store = configureStore({
843
+ reducer: {
844
+ user: userReducer,
845
+ cart: cartReducer,
846
+ },
847
+ });
848
+
849
+ // That's it! DevTools connection is automatic
850
+ ```
851
+
852
+ #### Legacy Redux
853
+
854
+ ```jsx
855
+ import { createStore, applyMiddleware, compose } from 'redux';
856
+
857
+ const composeEnhancers =
858
+ window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
859
+
860
+ const store = createStore(
861
+ rootReducer,
862
+ composeEnhancers(applyMiddleware(...middleware))
863
+ );
864
+
865
+ window.store = store; // For React Debugger
866
+ ```
867
+
868
+ ---
869
+
870
+ ### 💡 Pro Tips
871
+
872
+ #### 1. Quick State Reset
873
+
874
+ Made too many edits? Click `⟲` to reset all values to original.
875
+
876
+ #### 2. Test Loading States
877
+
878
+ ```json
879
+ Type: posts/fetchPending
880
+ Payload: {}
881
+ // Then check your loading UI
882
+
883
+ Type: posts/fetchSuccess
884
+ Payload: { "posts": [...] }
885
+ // Check success state
886
+ ```
887
+
888
+ #### 3. Simulate Errors
889
+
890
+ ```json
891
+ Type: posts/fetchError
892
+ Payload: { "error": "Network timeout" }
893
+ // Check error handling UI
894
+ ```
895
+
896
+ #### 4. Debug Selectors
897
+
898
+ Edit state values to see if selectors update correctly:
899
+ ```
900
+ user.subscription: "free" → "premium"
901
+ // Watch if premium features appear
902
+ ```
903
+
904
+ #### 5. Test Permissions
905
+
906
+ ```
907
+ user.role: "user" → "admin"
908
+ // Verify admin-only features show/hide
909
+ ```
910
+
911
+ ---
912
+
913
+ ### ⚠️ Troubleshooting
914
+
915
+ #### "Redux not detected"
916
+
917
+ Check the Setup Guide shown in the tab:
918
+
919
+ 1. Verify Redux is actually used in the app
920
+ 2. Expose store via `window.store`
921
+ 3. Install Redux DevTools browser extension
922
+ 4. Refresh the page
923
+
924
+ #### State doesn't update after edit
925
+
926
+ 1. Click `🔄` Refresh button
927
+ 2. Check browser console for errors
928
+ 3. Verify reducer handles the action
929
+
930
+ #### Actions not appearing
931
+
932
+ 1. Make sure Recording is enabled (green badge)
933
+ 2. Actions must be dispatched after opening DevTools
934
+ 3. Check if middleware is blocking actions
935
+
936
+ ---
937
+
938
+ ## Quick Reference
939
+
940
+ ### When to Use Each Tab
941
+
942
+ | Scenario | Tab |
943
+ |----------|-----|
944
+ | "What just happened?" | Timeline |
945
+ | "Is my code correct?" | UI & State |
946
+ | "Why is it slow?" | Performance |
947
+ | "Is there a leak?" | Memory |
948
+ | "Are my effects right?" | Side Effects |
949
+ | "Why does it jump?" | CLS |
950
+ | "What's in my store?" | Redux |
951
+
952
+ ### Metric Thresholds
953
+
954
+ | Metric | Good | Warning | Poor |
955
+ |--------|------|---------|------|
956
+ | Render time | < 16ms | 16-50ms | > 50ms |
957
+ | Memory usage | < 70% | 70-90% | > 90% |
958
+ | CLS score | < 0.1 | 0.1-0.25 | > 0.25 |
959
+ | FCP | < 1.8s | 1.8-3s | > 3s |
960
+ | LCP | < 2.5s | 2.5-4s | > 4s |