0
# Component Tracking and Notifications
1
2
Built-in component tracking and notification system that provides detailed analysis of re-render causes and patterns.
3
4
## Capabilities
5
6
### Update Information Structure
7
8
Complete information about a component re-render event, provided to notifiers:
9
10
```typescript { .api }
11
interface UpdateInfo {
12
/** The component that re-rendered */
13
Component: React.Component;
14
15
/** Display name of the component */
16
displayName: string;
17
18
/** Previous props object */
19
prevProps: any;
20
21
/** Previous state object */
22
prevState: any;
23
24
/** Next props object */
25
nextProps: any;
26
27
/** Next state object */
28
nextState: any;
29
30
/** Previous hook result (for hook updates) */
31
prevHookResult: any;
32
33
/** Next hook result (for hook updates) */
34
nextHookResult: any;
35
36
/** Detailed reason for the update */
37
reason: ReasonForUpdate;
38
39
/** WDYR options used for this tracking */
40
options: WhyDidYouRenderOptions;
41
42
/** Name of the hook (if this is a hook update) */
43
hookName?: string;
44
45
/** Previous owner component (for owner tracking) */
46
prevOwner?: React.Component;
47
48
/** Next owner component (for owner tracking) */
49
nextOwner?: React.Component;
50
}
51
```
52
53
### Re-render Reason Analysis
54
55
Detailed analysis of why a component re-rendered:
56
57
```typescript { .api }
58
interface ReasonForUpdate {
59
/** Array of hook-related changes that caused the re-render */
60
hookDifferences: HookDifference[];
61
62
/** Whether props changes contributed to the re-render */
63
propsDifferences: boolean;
64
65
/** Whether state changes contributed to the re-render */
66
stateDifferences: boolean;
67
68
/** Owner component differences (when logOwnerReasons is enabled) */
69
ownerDifferences?: {
70
propsDifferences?: HookDifference[];
71
stateDifferences?: HookDifference[];
72
hookDifferences?: Array<{
73
hookName: string;
74
differences: HookDifference[];
75
}>;
76
};
77
}
78
79
interface HookDifference {
80
/** Path string to the changed value (e.g., "0" for useState, "items[2].name" for nested) */
81
pathString: string;
82
83
/** Type of difference detected (e.g., "different", "deepEquals") */
84
diffType: string;
85
86
/** Previous value before the change */
87
prevValue: any;
88
89
/** Next value after the change */
90
nextValue: any;
91
}
92
```
93
94
### Default Notifier
95
96
Built-in notification handler that logs re-render information to the console:
97
98
```typescript { .api }
99
/**
100
* Default notification handler for component re-render events
101
* Logs detailed information about why the component re-rendered
102
* @param updateInfo - Complete information about the component update
103
*/
104
function defaultNotifier(updateInfo: UpdateInfo): void;
105
```
106
107
**Usage Example:**
108
109
```javascript
110
import whyDidYouRender from '@welldone-software/why-did-you-render';
111
112
// The default notifier is used automatically
113
whyDidYouRender(React, {
114
trackAllPureComponents: true
115
});
116
117
// Access the default notifier directly if needed
118
console.log(whyDidYouRender.defaultNotifier);
119
```
120
121
### Custom Notifiers
122
123
Create custom notification handlers for specialized logging or integration with monitoring systems:
124
125
```typescript { .api }
126
/**
127
* Custom notifier function type
128
* @param updateInfo - Information about the component update
129
*/
130
type Notifier = (updateInfo: UpdateInfo) => void;
131
```
132
133
**Usage Examples:**
134
135
```javascript
136
// Custom notifier that sends data to analytics
137
const analyticsNotifier = (updateInfo) => {
138
analytics.track('component_rerender', {
139
componentName: updateInfo.displayName,
140
hasPropsChanges: updateInfo.reason.propsDifferences,
141
hasStateChanges: updateInfo.reason.stateDifferences,
142
hookChanges: updateInfo.reason.hookDifferences.length
143
});
144
};
145
146
whyDidYouRender(React, {
147
trackAllPureComponents: true,
148
notifier: analyticsNotifier
149
});
150
151
// Custom notifier that filters by component type
152
const filteredNotifier = (updateInfo) => {
153
if (updateInfo.displayName.startsWith('Heavy')) {
154
console.warn(`Performance concern: ${updateInfo.displayName} re-rendered`);
155
whyDidYouRender.defaultNotifier(updateInfo);
156
}
157
};
158
159
whyDidYouRender(React, {
160
notifier: filteredNotifier
161
});
162
```
163
164
### Component Display Names
165
166
Utility for getting meaningful component names for logging:
167
168
```typescript { .api }
169
/**
170
* Gets a display name for a component
171
* @param Component - React component to get name for
172
* @returns String display name
173
*/
174
function getDisplayName(Component: React.ComponentType): string;
175
```
176
177
### Component Type Detection
178
179
Utilities for identifying different types of React components:
180
181
```typescript { .api }
182
/**
183
* Determines if a component is a React.memo wrapped component
184
* @param Component - Component to check
185
* @returns Boolean indicating if it's a memo component
186
*/
187
function isMemoComponent(Component: any): boolean;
188
189
/**
190
* Determines if a component is a React.forwardRef wrapped component
191
* @param Component - Component to check
192
* @returns Boolean indicating if it's a forwardRef component
193
*/
194
function isForwardRefComponent(Component: any): boolean;
195
196
/**
197
* Determines if a component is a React class component
198
* @param Component - Component to check
199
* @returns Boolean indicating if it's a class component
200
*/
201
function isReactClassComponent(Component: any): boolean;
202
```
203
204
### Tracking Eligibility
205
206
Function to determine if a component should be tracked based on configuration:
207
208
```typescript { .api }
209
/**
210
* Determines if a component should be tracked for re-renders
211
* @param Component - Component to evaluate
212
* @param options - Tracking context options
213
* @returns Boolean indicating if component should be tracked
214
*/
215
function shouldTrack(
216
Component: React.ComponentType,
217
options: { isHookChange?: boolean }
218
): boolean;
219
220
/**
221
* Gets default props for a component (handles both function and class components)
222
* @param Component - Component to get default props for
223
* @returns Default props object or empty object
224
*/
225
function getDefaultProps(Component: React.ComponentType): object;
226
227
/**
228
* Gets update information for a component re-render
229
* @param options - Component and render information
230
* @returns Structured update information for notifiers
231
*/
232
function getUpdateInfo(options: {
233
Component: React.ComponentType;
234
displayName: string;
235
hookName?: string;
236
prevHookResult?: any;
237
nextHookResult?: any;
238
prevProps?: any;
239
nextProps?: any;
240
prevState?: any;
241
nextState?: any;
242
}): UpdateInfo;
243
```
244
245
## Advanced Tracking Features
246
247
### Owner Component Tracking
248
249
When `logOwnerReasons` is enabled, the library tracks which parent components cause child re-renders:
250
251
```typescript { .api }
252
/**
253
* Stores owner component data for render tracking
254
* @param element - React element to store owner data for
255
*/
256
function storeOwnerData(element: React.Element): void;
257
258
/**
259
* Gets the current owner component during rendering
260
* @returns Current owner component or null
261
*/
262
function getCurrentOwner(): React.Component | null;
263
```
264
265
### Hot Reload Integration
266
267
Built-in hot reload detection to prevent false positives during development:
268
269
```typescript { .api }
270
/**
271
* Creates a notifier that handles hot reload scenarios
272
* @param hotReloadBufferMs - Buffer time in milliseconds
273
* @returns Configured notifier function
274
*/
275
function createDefaultNotifier(hotReloadBufferMs?: number): Notifier;
276
```
277
278
**Usage Example:**
279
280
```javascript
281
whyDidYouRender(React, {
282
hotReloadBufferMs: 1000, // 1 second buffer
283
trackAllPureComponents: true
284
});
285
```
286
287
## Console Output Customization
288
289
Customize the appearance of console output:
290
291
```typescript { .api }
292
interface ConsoleOptions {
293
/** Color for component names (default: '#058') */
294
titleColor?: string;
295
296
/** Color for diff property names (default: 'blue') */
297
diffNameColor?: string;
298
299
/** Color for diff property paths (default: 'red') */
300
diffPathColor?: string;
301
302
/** Background color for text (default: 'white') */
303
textBackgroundColor?: string;
304
305
/** Use console.log instead of console.group (default: false) */
306
onlyLogs?: boolean;
307
308
/** Use console.groupCollapsed (default: false) */
309
collapseGroups?: boolean;
310
}
311
```
312
313
**Usage Example:**
314
315
```javascript
316
whyDidYouRender(React, {
317
trackAllPureComponents: true,
318
titleColor: '#ff6b6b',
319
diffNameColor: '#4ecdc4',
320
diffPathColor: '#45b7d1',
321
collapseGroups: true
322
});
323
```