or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

hook-tracking.mddocs/

0

# Hook Tracking

1

2

Advanced hook tracking system for monitoring React hooks like useState, useReducer, and custom hooks to detect unnecessary re-renders caused by hook state changes.

3

4

## Capabilities

5

6

### Hook Tracking Configuration

7

8

Built-in configuration for tracking standard React hooks:

9

10

```typescript { .api }

11

interface HookConfig {

12

/** Path to the tracked value within the hook result */

13

path?: string;

14

15

/** Path to dependencies array for memoization hooks */

16

dependenciesPath?: string;

17

18

/** Whether to suppress reporting for this hook type */

19

dontReport?: boolean;

20

}

21

22

/**

23

* Built-in hook tracking configuration

24

*/

25

const hooksConfig: {

26

useState: { path: '0' };

27

useReducer: { path: '0' };

28

useContext: undefined;

29

useSyncExternalStore: undefined;

30

useMemo: { dependenciesPath: '1', dontReport: true };

31

useCallback: { dependenciesPath: '1', dontReport: true };

32

};

33

```

34

35

### Extra Hook Tracking

36

37

Support for tracking additional hooks beyond the built-in React hooks:

38

39

```typescript { .api }

40

/**

41

* Configuration for tracking additional hooks

42

* First element is the hook parent object, second is the hook name

43

*/

44

type ExtraHookToTrack = [any, string];

45

```

46

47

**Usage Examples:**

48

49

```javascript

50

import whyDidYouRender from '@welldone-software/why-did-you-render';

51

import { useSelector } from 'react-redux';

52

53

// Track React-Redux useSelector hook

54

whyDidYouRender(React, {

55

trackHooks: true,

56

trackExtraHooks: [

57

[require('react-redux'), 'useSelector']

58

]

59

});

60

61

// Track custom hooks from your own library

62

import * as myHooks from './my-custom-hooks';

63

64

whyDidYouRender(React, {

65

trackHooks: true,

66

trackExtraHooks: [

67

[myHooks, 'useCustomState'],

68

[myHooks, 'useAsyncData']

69

]

70

});

71

```

72

73

### Hook Change Detection

74

75

System for detecting and analyzing hook state changes:

76

77

```typescript { .api }

78

interface HookDifference {

79

/** Path string to the changed value (e.g., "0" for useState result) */

80

pathString: string;

81

82

/** Type of difference detected (e.g., "different", "deepEquals", "same") */

83

diffType: string;

84

85

/** Previous hook value before the change */

86

prevValue: any;

87

88

/** Next hook value after the change */

89

nextValue: any;

90

}

91

```

92

93

### Hook Tracking Function

94

95

Internal function that wraps hooks for tracking (exposed for advanced usage):

96

97

```typescript { .api }

98

/**

99

* Tracks changes in hook results and reports unnecessary re-renders

100

* @param hookName - Name of the hook being tracked

101

* @param hookTrackingConfig - Configuration for how to track this hook

102

* @param rawHookResult - The raw result returned by the hook

103

* @returns The unmodified hook result

104

*/

105

function trackHookChanges(

106

hookName: string,

107

hookTrackingConfig: { path?: string },

108

rawHookResult: any

109

): any;

110

```

111

112

### Hook Information Storage

113

114

Data structures for storing hook information during render cycles:

115

116

```typescript { .api }

117

interface HookInfo {

118

/** Name of the hook */

119

hookName: string;

120

121

/** Current result/value of the hook */

122

result: any;

123

}

124

125

/**

126

* Map that stores hook information for the current render cycle

127

* Keys are component instances, values are arrays of HookInfo

128

*/

129

type HooksInfoMap = WeakMap<React.Component, HookInfo[]>;

130

```

131

132

## Hook Integration Examples

133

134

### useState Tracking

135

136

```javascript

137

import React, { useState } from 'react';

138

import whyDidYouRender from '@welldone-software/why-did-you-render';

139

140

whyDidYouRender(React, {

141

trackHooks: true

142

});

143

144

const Counter = () => {

145

const [count, setCount] = useState(0);

146

const [name, setName] = useState('Counter');

147

148

return (

149

<div>

150

<h1>{name}: {count}</h1>

151

<button onClick={() => setCount(count + 1)}>Increment</button>

152

{/* This will trigger a warning if name doesn't actually change */}

153

<button onClick={() => setName('Counter')}>Set Same Name</button>

154

</div>

155

);

156

};

157

158

Counter.whyDidYouRender = true;

159

```

160

161

### useSelector Tracking (React-Redux)

162

163

```javascript

164

import React from 'react';

165

import { useSelector } from 'react-redux';

166

import whyDidYouRender from '@welldone-software/why-did-you-render';

167

168

whyDidYouRender(React, {

169

trackHooks: true,

170

trackExtraHooks: [

171

[require('react-redux'), 'useSelector']

172

]

173

});

174

175

const UserProfile = ({ userId }) => {

176

// This will be tracked for unnecessary re-renders

177

const user = useSelector(state => state.users[userId]);

178

const isLoading = useSelector(state => state.ui.loading);

179

180

if (isLoading) return <div>Loading...</div>;

181

182

return (

183

<div>

184

<h1>{user.name}</h1>

185

<p>{user.email}</p>

186

</div>

187

);

188

};

189

190

UserProfile.whyDidYouRender = true;

191

```

192

193

### Custom Hook Tracking

194

195

```javascript

196

import React, { useState, useEffect } from 'react';

197

import whyDidYouRender from '@welldone-software/why-did-you-render';

198

199

// Custom hook

200

const useApi = (url) => {

201

const [data, setData] = useState(null);

202

const [loading, setLoading] = useState(true);

203

204

useEffect(() => {

205

fetch(url)

206

.then(response => response.json())

207

.then(result => {

208

setData(result);

209

setLoading(false);

210

});

211

}, [url]);

212

213

return { data, loading };

214

};

215

216

// Track the custom hook

217

whyDidYouRender(React, {

218

trackHooks: true,

219

trackExtraHooks: [

220

[{ useApi }, 'useApi']

221

]

222

});

223

224

const DataComponent = ({ endpoint }) => {

225

const { data, loading } = useApi(endpoint);

226

227

if (loading) return <div>Loading...</div>;

228

return <div>{JSON.stringify(data)}</div>;

229

};

230

231

DataComponent.whyDidYouRender = true;

232

```

233

234

## Hook Tracking Configuration Options

235

236

### Enabling Hook Tracking

237

238

```typescript { .api }

239

interface HookTrackingOptions {

240

/** Whether to track React hooks for state changes */

241

trackHooks?: boolean;

242

243

/** Additional hooks to track beyond built-in React hooks */

244

trackExtraHooks?: Array<ExtraHookToTrack>;

245

}

246

```

247

248

### Hook-Specific Configuration

249

250

```javascript

251

// Example of comprehensive hook tracking setup

252

whyDidYouRender(React, {

253

trackHooks: true,

254

trackExtraHooks: [

255

// Track React-Redux hooks

256

[require('react-redux'), 'useSelector'],

257

[require('react-redux'), 'useDispatch'],

258

259

// Track React Router hooks

260

[require('react-router-dom'), 'useParams'],

261

[require('react-router-dom'), 'useLocation'],

262

263

// Track custom application hooks

264

[require('./hooks/useAuth'), 'useAuth'],

265

[require('./hooks/useApi'), 'useApi']

266

]

267

});

268

```

269

270

## Hook Difference Types

271

272

The library categorizes hook changes into different types:

273

274

```typescript { .api }

275

/**

276

* Types of differences that can be detected in hook values

277

*/

278

enum DiffTypes {

279

/** Values are identical (===) */

280

same = 'same',

281

282

/** Values are different */

283

different = 'different',

284

285

/** Values are deeply equal but not identical */

286

deepEquals = 'deepEquals'

287

}

288

```

289

290

## Advanced Hook Features

291

292

### Dependency Tracking

293

294

For memoization hooks like `useMemo` and `useCallback`, the library tracks dependencies:

295

296

```javascript

297

const MyComponent = ({ items }) => {

298

// Dependencies array [items.length] will be tracked

299

const expensiveValue = useMemo(() => {

300

return items.reduce((sum, item) => sum + item.value, 0);

301

}, [items.length]); // This dependency array is monitored

302

303

return <div>{expensiveValue}</div>;

304

};

305

```

306

307

### Hook Result Path Tracking

308

309

For hooks that return arrays or objects, specific paths can be tracked:

310

311

```javascript

312

// useState returns [value, setter] - path "0" tracks the value

313

const [count, setCount] = useState(0); // Tracks count changes

314

315

// useReducer returns [state, dispatch] - path "0" tracks the state

316

const [state, dispatch] = useReducer(reducer, initialState); // Tracks state changes

317

```

318

319

### Hook Name Customization

320

321

You can provide custom names for better debugging:

322

323

```javascript

324

whyDidYouRender(React, {

325

trackHooks: true,

326

trackExtraHooks: [

327

[myHooksLibrary, 'useComplexState', { customName: 'ComplexStateHook' }]

328

]

329

});

330

```