React Review Audit

Author: react-doctor[bot]Created May 18, 2026Updated May 20, 2026
10 errors, ⚠️ 228 warnings 81 score
Copy as prompt
Fix the following React Review diagnostics in my codebase.

## Errors (10)

1. [error] jsx-key — packages/scan/src/web/views/notifications/collapsed-event.tsx:165
   Missing "key" prop for element in iterator.

2. [error] no-mutable-in-deps — packages/scan/src/web/views/notifications/popover.tsx:73
   "triggerRef.current" in deps — refs are mutable and don't trigger re-renders, so React won't re-run this effect when it changes. Read the ref inside the effect body instead

3. [error] effect-needs-cleanup — packages/scan/src/web/views/notifications/notifications.tsx:227
   useEffect schedules `setTimeout(...)` but never returns a cleanup — leaks the registration on every re-run and on unmount. Return a cleanup function that calls clearTimeout(...)

4. [error] effect-needs-cleanup — packages/scan/src/web/views/notifications/slowdown-history.tsx:27
   useEffect schedules `setTimeout(...)` but never returns a cleanup — leaks the registration on every re-run and on unmount. Return a cleanup function that calls clearTimeout(...)

5. [error] effect-needs-cleanup — packages/scan/src/web/views/notifications/slowdown-history.tsx:339
   useEffect schedules `setTimeout(...)` but never returns a cleanup — leaks the registration on every re-run and on unmount. Return a cleanup function that calls clearTimeout(...)

6. [error] nextjs-async-client-component — packages/website/public/auto.global.js:2
   Async client component "B" — client components cannot be async

7. [error] nextjs-async-client-component — packages/website/public/auto.global.js:2
   Async client component "Pa" — client components cannot be async

8. [error] nextjs-async-client-component — packages/website/public/auto.global.js:2
   Async client component "Ul" — client components cannot be async

9. [error] nextjs-async-client-component — packages/website/public/auto.global.js:2
   Async client component "Jl" — client components cannot be async

10. [error] nextjs-async-client-component — packages/website/public/auto.global.js:2
   Async client component "Tc" — client components cannot be async

## Warnings (228)

11. [warning] no-cascading-set-state — kitchen-sink/src/examples/sierpinski/index.tsx:27
   3 setState calls in a single useEffect — consider using useReducer or deriving state

12. [warning] click-events-have-key-events — kitchen-sink/src/examples/e2e-fixture/index.tsx:46
   Enforce a clickable non-interactive element has at least one keyboard event listener.

13. [warning] no-static-element-interactions — kitchen-sink/src/examples/e2e-fixture/index.tsx:46
   Static HTML elements with event handlers require a role.

14. [warning] no-react19-deprecated-apis — kitchen-sink/src/examples/e2e-fixture/index.tsx:1
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

15. [warning] no-uncontrolled-input — kitchen-sink/src/examples/todo-list/index.tsx:92
   <input value={...}> with no `onChange` or `readOnly` — React renders this as a silently read-only field

16. [warning] rerender-functional-setstate — kitchen-sink/src/examples/todo-list/index.tsx:88
   setIndex(index + ...) — use functional update to avoid stale closures

17. [warning] iframe-has-title — kitchen-sink/src/main.tsx:39
   Missing `title` attribute for the `iframe` element.

18. [warning] design-no-default-tailwind-palette — kitchen-sink/src/main.tsx:19
   border-gray-950 reads as the Tailwind template default — use zinc (true neutral), neutral (warmer), or stone (warmest)

19. [warning] design-no-bold-heading — kitchen-sink/src/main.tsx:20
   font-bold on <h1> crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)

20. [warning] design-no-default-tailwind-palette — kitchen-sink/src/main.tsx:24
   border-gray-950 reads as the Tailwind template default — use zinc (true neutral), neutral (warmer), or stone (warmest)

21. [warning] design-no-default-tailwind-palette — kitchen-sink/src/main.tsx:29
   border-gray-950 reads as the Tailwind template default — use zinc (true neutral), neutral (warmer), or stone (warmest)

22. [warning] js-batch-dom-css — packages/extension/src/inject/notification.ts:36
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

23. [warning] js-batch-dom-css — packages/extension/src/inject/notification.ts:130
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

24. [warning] js-set-map-lookups — packages/scan/src/core/index.ts:299
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

25. [warning] js-batch-dom-css — packages/scan/src/core/notifications/outline-overlay.ts:172
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

26. [warning] js-batch-dom-css — packages/scan/src/core/notifications/outline-overlay.ts:176
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

27. [warning] js-batch-dom-css — packages/scan/src/core/notifications/outline-overlay.ts:177
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

28. [warning] js-batch-dom-css — packages/scan/src/core/notifications/outline-overlay.ts:178
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

29. [warning] js-batch-dom-css — packages/scan/src/core/notifications/outline-overlay.ts:179
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

30. [warning] js-batch-dom-css — packages/scan/src/core/notifications/outline-overlay.ts:195
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

31. [warning] no-pure-black-background — packages/scan/src/web/toolbar.tsx:22
   Pure black background (bg-black) looks harsh — use a near-black tinted toward your brand hue (e.g. bg-gray-950)

32. [warning] no-pure-black-background — packages/scan/src/web/toolbar.tsx:27
   Pure black background (bg-black) looks harsh — use a near-black tinted toward your brand hue (e.g. bg-gray-950)

33. [warning] no-giant-component — packages/scan/src/web/views/inspector/components-tree/index.tsx:386
   Component "ComponentsTree" is 792 lines — consider breaking it into smaller focused components

34. [warning] design-no-redundant-size-axes — packages/scan/src/web/views/inspector/components-tree/index.tsx:1072
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

35. [warning] design-no-redundant-size-axes — packages/scan/src/web/views/inspector/components-tree/index.tsx:1086
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

36. [warning] design-no-redundant-size-axes — packages/scan/src/web/views/inspector/components-tree/index.tsx:1102
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

37. [warning] async-await-in-loop — packages/scan/src/new-outlines/index.ts:153
   await inside a while-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

38. [warning] js-batch-dom-css — packages/scan/src/new-outlines/index.ts:304
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

39. [warning] js-batch-dom-css — packages/scan/src/new-outlines/index.ts:305
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

40. [warning] js-batch-dom-css — packages/scan/src/new-outlines/index.ts:306
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

41. [warning] js-batch-dom-css — packages/scan/src/new-outlines/index.ts:307
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

42. [warning] js-batch-dom-css — packages/scan/src/new-outlines/index.ts:318
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

43. [warning] js-batch-dom-css — packages/scan/src/new-outlines/index.ts:381
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

44. [warning] client-passive-event-listeners — packages/scan/src/new-outlines/index.ts:407
   "scroll" listener without { passive: true } — blocks scrolling performance. Only add { passive: true } if the handler does NOT call event.preventDefault() (passive listeners silently ignore preventDefault())

45. [warning] rerender-transitions-scroll — packages/scan/src/new-outlines/index.ts:411
   setState in a "scroll" handler triggers re-renders at scroll/pointer frequency — wrap in startTransition (mark as non-urgent), use useDeferredValue, or stash in a ref + rAF throttle

46. [warning] js-flatmap-filter — packages/scan/src/web/views/inspector/timeline/utils.ts:148
   .map().filter(Boolean) iterates twice — use .flatMap() to transform and filter in a single pass

47. [warning] no-cascading-set-state — packages/scan/src/web/views/notifications/collapsed-event.tsx:36
   11 setState calls in a single useEffect — consider using useReducer or deriving state

48. [warning] js-set-map-lookups — packages/scan/src/web/views/inspector/utils.ts:1357
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

49. [warning] js-set-map-lookups — packages/scan/src/web/views/inspector/utils.ts:1394
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

50. [warning] js-set-map-lookups — packages/scan/src/web/views/inspector/utils.ts:1446
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

51. [warning] js-set-map-lookups — packages/scan/src/web/views/inspector/utils.ts:1865
   array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups

52. [warning] js-set-map-lookups — packages/scan/src/web/views/inspector/utils.ts:1888
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

53. [warning] js-tosorted-immutable — packages/scan/src/polyfills.ts:4
   [...array].sort() — use array.toSorted() for immutable sorting (ES2023)

54. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:5
   Unknown property found

55. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:5
   Unknown property found

56. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:5
   Unknown property found

57. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:18
   Unknown property found

58. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:18
   Unknown property found

59. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:18
   Unknown property found

60. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:23
   Unknown property found

61. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:23
   Unknown property found

62. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:23
   Unknown property found

63. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:27
   Unknown property found

64. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:27
   Unknown property found

65. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:27
   Unknown property found

66. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:31
   Unknown property found

67. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:31
   Unknown property found

68. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:31
   Unknown property found

69. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:36
   Unknown property found

70. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:36
   Unknown property found

71. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:36
   Unknown property found

72. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:45
   Unknown property found

73. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:45
   Unknown property found

74. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:45
   Unknown property found

75. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:51
   Unknown property found

76. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:51
   Unknown property found

77. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:51
   Unknown property found

78. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:56
   Unknown property found

79. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:56
   Unknown property found

80. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:56
   Unknown property found

81. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:60
   Unknown property found

82. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:60
   Unknown property found

83. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:60
   Unknown property found

84. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:64
   Unknown property found

85. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:64
   Unknown property found

86. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:64
   Unknown property found

87. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:72
   Unknown property found

88. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:72
   Unknown property found

89. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:72
   Unknown property found

90. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:78
   Unknown property found

91. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:78
   Unknown property found

92. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:78
   Unknown property found

93. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:84
   Unknown property found

94. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:84
   Unknown property found

95. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:84
   Unknown property found

96. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:89
   Unknown property found

97. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:89
   Unknown property found

98. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:89
   Unknown property found

99. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:94
   Unknown property found

100. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:94
   Unknown property found

101. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:94
   Unknown property found

102. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:99
   Unknown property found

103. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:99
   Unknown property found

104. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:99
   Unknown property found

105. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:104
   Unknown property found

106. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:104
   Unknown property found

107. [warning] no-unknown-property — packages/scan/src/web/components/svg-sprite/index.tsx:104
   Unknown property found

108. [warning] js-cache-property-access — packages/scan/src/web/views/inspector/whats-changed/use-change-store.ts:123
   aggregatedChanges.contextChanges.set is read 3 times inside this loop — hoist into a const at the top of the loop body

109. [warning] js-cache-property-access — packages/scan/src/web/views/inspector/whats-changed/use-change-store.ts:128
   change.contextType.toString is read 3 times inside this loop — hoist into a const at the top of the loop body

110. [warning] design-no-default-tailwind-palette — packages/scan/src/web/views/inspector/diff-value.tsx:55
   text-gray-500 reads as the Tailwind template default — use zinc (true neutral), neutral (warmer), or stone (warmest)

111. [warning] design-no-default-tailwind-palette — packages/scan/src/web/views/inspector/diff-value.tsx:81
   text-gray-500 reads as the Tailwind template default — use zinc (true neutral), neutral (warmer), or stone (warmest)

112. [warning] design-no-default-tailwind-palette — packages/scan/src/web/views/inspector/diff-value.tsx:118
   text-gray-500 reads as the Tailwind template default — use zinc (true neutral), neutral (warmer), or stone (warmest)

113. [warning] no-array-index-as-key — packages/scan/src/web/views/inspector/diff-value.tsx:143
   Array index "index" used as key — causes bugs when list is reordered or filtered

114. [warning] js-flatmap-filter — packages/scan/src/core/notifications/event-tracking.ts:290
   .map().filter(Boolean) iterates twice — use .flatMap() to transform and filter in a single pass

115. [warning] no-giant-component — packages/scan/src/web/views/inspector/overlay/index.tsx:48
   Component "ScanOverlay" is 684 lines — consider breaking it into smaller focused components

116. [warning] no-cascading-set-state — packages/scan/src/web/views/inspector/what-changed.tsx:36
   3 setState calls in a single useEffect — consider using useReducer or deriving state

117. [warning] js-combine-iterations — packages/scan/src/web/views/inspector/what-changed.tsx:49
   .filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of

118. [warning] no-render-in-render — packages/scan/src/web/views/inspector/what-changed.tsx:323
   Inline render function "renderName()" — extract to a separate component for proper reconciliation

119. [warning] no-array-index-as-key — packages/scan/src/web/views/inspector/what-changed.tsx:452
   Array index "i" used as key — causes bugs when list is reordered or filtered

120. [warning] js-batch-dom-css — packages/scan/src/web/views/inspector/flash-overlay.ts:64
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

121. [warning] js-batch-dom-css — packages/scan/src/web/views/inspector/flash-overlay.ts:68
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

122. [warning] no-unknown-property — pack