or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

component-tracking.mdcore-setup.mdhook-tracking.mdindex.md

component-tracking.mddocs/

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

```