Skip to content

React Review Audit #17

Description

@react-doctor
40 errors, ⚠️ 143 warnings 76 score
Copy as prompt
Fix the following React Review diagnostics in my codebase.

## Errors (40)

1. [error] require-reduced-motion — skills/budge/budge/package.json:0
   Project uses a motion library but has no prefers-reduced-motion handling — required for accessibility (WCAG 2.3.3)

2. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:342
   React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.

3. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:351
   React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

4. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:352
   React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

5. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:353
   React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

6. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:354
   React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

7. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:355
   React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

8. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:356
   React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

9. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:357
   React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

10. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:358
   React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

11. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:359
   React Hook "useRef" is called conditionally. React Hooks must be called in the exact same order in every component render.

12. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:360
   React Hook "useRef" is called conditionally. React Hooks must be called in the exact same order in every component render.

13. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:363
   React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

14. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:364
   React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

15. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:365
   React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

16. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:366
   React Hook "useRef" is called conditionally. React Hooks must be called in the exact same order in every component render.

17. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:367
   React Hook "useRef" is called conditionally. React Hooks must be called in the exact same order in every component render.

18. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:369
   React Hook "useRef" is called conditionally. React Hooks must be called in the exact same order in every component render.

19. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:370
   React Hook "useRef" is called conditionally. React Hooks must be called in the exact same order in every component render.

20. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:371
   React Hook "useRef" is called conditionally. React Hooks must be called in the exact same order in every component render.

21. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:372
   React Hook "useRef" is called conditionally. React Hooks must be called in the exact same order in every component render.

22. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:373
   React Hook "useRef" is called conditionally. React Hooks must be called in the exact same order in every component render.

23. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:374
   React Hook "useRef" is called conditionally. React Hooks must be called in the exact same order in every component render.

24. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:375
   React Hook "useRef" is called conditionally. React Hooks must be called in the exact same order in every component render.

25. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:377
   React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.

26. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:379
   React Hook "useCallback" is called conditionally. React Hooks must be called in the exact same order in every component render.

27. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:394
   React Hook "useCallback" is called conditionally. React Hooks must be called in the exact same order in every component render.

28. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:402
   React Hook "useCallback" is called conditionally. React Hooks must be called in the exact same order in every component render.

29. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:415
   React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.

30. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:420
   React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.

31. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:453
   React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.

32. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:460
   React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.

33. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:473
   React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.

34. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:507
   React Hook "useCallback" is called conditionally. React Hooks must be called in the exact same order in every component render.

35. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:521
   React Hook "useCallback" is called conditionally. React Hooks must be called in the exact same order in every component render.

36. [error] rules-of-hooks — skills/budge/website/app/__budge.tsx:533
   React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.

37. [error] effect-needs-cleanup — skills/budge/website/components/budge-me-paper-preview.tsx:422
   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(...)

38. [error] effect-needs-cleanup — skills/budge/website/components/budge-me-paper-preview.tsx:716
   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(...)

39. [error] rules-of-hooks — skills/budge/website/public/budge.iife.js:82
   React Hook "useEffect" is called in function "Anonymous" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use".

40. [error] no-nested-component-definition — skills/budge/website/public/budge.iife.js:82
   Component "C" defined inside "Zu" — creates new instance every render, destroying state

## Warnings (143)

41. [warning] js-batch-dom-css — skills/budge/budge/src/entry.tsx:240
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

42. [warning] js-batch-dom-css — skills/budge/budge/src/entry.tsx:241
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

43. [warning] js-batch-dom-css — skills/budge/budge/src/entry.tsx:242
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

44. [warning] js-batch-dom-css — skills/budge/budge/src/entry.tsx:243
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

45. [warning] js-batch-dom-css — skills/budge/budge/src/entry.tsx:244
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

46. [warning] js-batch-dom-css — skills/budge/budge/src/entry.tsx:245
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

47. [warning] js-flatmap-filter — skills/budge/budge/src/entry.tsx:429
   .map().filter(Boolean) iterates twice — use .flatMap() to transform and filter in a single pass

48. [warning] async-defer-await — skills/budge/budge/src/entry.tsx:680
   await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast

49. [warning] js-flatmap-filter — skills/budge/budge/src/budge.tsx:109
   .map().filter(Boolean) iterates twice — use .flatMap() to transform and filter in a single pass

50. [warning] no-giant-component — skills/budge/budge/src/budge.tsx:446
   Component "Budge" is 800 lines — consider breaking it into smaller focused components

51. [warning] prefer-useReducer — skills/budge/budge/src/budge.tsx:446
   Component "Budge" has 19 useState calls — consider useReducer for related state

52. [warning] rerender-state-only-in-handlers — skills/budge/budge/src/budge.tsx:457
   useState "showPrompt" is updated but never read in the component's return — use useRef so updates don't trigger re-renders

53. [warning] rerender-state-only-in-handlers — skills/budge/budge/src/budge.tsx:458
   useState "pressedButton" is updated but never read in the component's return — use useRef so updates don't trigger re-renders

54. [warning] no-cascading-set-state — skills/budge/budge/src/budge.tsx:529
   8 setState calls in a single useEffect — consider using useReducer or deriving state

55. [warning] no-cascading-set-state — skills/budge/budge/src/budge.tsx:870
   27 setState calls in a single useEffect — consider using useReducer or deriving state

56. [warning] no-outline-none — skills/budge/budge/src/budge.tsx:1032
   outline: none removes keyboard focus visibility — use :focus-visible styling instead, or provide a box-shadow focus ring

57. [warning] no-z-index-9999 — skills/budge/budge/src/budge.tsx:1032
   z-index: 2147483646 is arbitrarily high — use a deliberate z-index scale (1–50). Extreme values signal a stacking context problem, not a fix

58. [warning] no-inline-exhaustive-style — skills/budge/budge/src/budge.tsx:1041
   14 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

59. [warning] no-inline-exhaustive-style — skills/budge/budge/src/budge.tsx:1064
   10 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

60. [warning] no-inline-exhaustive-style — skills/budge/budge/src/budge.tsx:1089
   8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

61. [warning] no-inline-bounce-easing — skills/budge/budge/src/budge.tsx:1112
   Bounce/elastic easing feels dated — real objects decelerate smoothly. Use ease-out or cubic-bezier(0.16, 1, 0.3, 1) instead

62. [warning] no-inline-exhaustive-style — skills/budge/budge/src/budge.tsx:1138
   8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

63. [warning] no-tiny-text — skills/budge/budge/src/budge.tsx:1155
   Font size 11px is too small — body text should be at least 12px for readability, 16px is ideal

64. [warning] no-inline-exhaustive-style — skills/budge/budge/src/budge.tsx:1161
   10 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

65. [warning] no-tiny-text — skills/budge/budge/src/budge.tsx:1165
   Font size 11px is too small — body text should be at least 12px for readability, 16px is ideal

66. [warning] no-inline-exhaustive-style — skills/budge/budge/src/budge.tsx:1178
   8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

67. [warning] no-tiny-text — skills/budge/budge/src/budge.tsx:1195
   Font size 11px is too small — body text should be at least 12px for readability, 16px is ideal

68. [warning] no-inline-exhaustive-style — skills/budge/budge/src/budge.tsx:1201
   10 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

69. [warning] no-tiny-text — skills/budge/budge/src/budge.tsx:1205
   Font size 11px is too small — body text should be at least 12px for readability, 16px is ideal

70. [warning] no-array-index-as-key — skills/budge/website/app/claude-spinner.tsx:42
   Array index "index" used as key — causes bugs when list is reordered or filtered

71. [warning] nextjs-missing-metadata — skills/budge/website/app/building-the-preview/page.tsx:1
   Page without metadata or generateMetadata export — hurts SEO

72. [warning] nextjs-no-a-element — skills/budge/website/app/building-the-preview/page.tsx:99
   Use next/link instead of <a> for internal links — enables client-side navigation and prefetching

73. [warning] design-no-em-dash-in-jsx-text — skills/budge/website/app/building-the-preview/page.tsx:108
   Em dash (—) in JSX text reads as model output — replace with comma, colon, semicolon, or parentheses

74. [warning] design-no-em-dash-in-jsx-text — skills/budge/website/app/building-the-preview/page.tsx:119
   Em dash (—) in JSX text reads as model output — replace with comma, colon, semicolon, or parentheses

75. [warning] design-no-em-dash-in-jsx-text — skills/budge/website/app/building-the-preview/page.tsx:128
   Em dash (—) in JSX text reads as model output — replace with comma, colon, semicolon, or parentheses

76. [warning] design-no-em-dash-in-jsx-text — skills/budge/website/app/building-the-preview/page.tsx:137
   Em dash (—) in JSX text reads as model output — replace with comma, colon, semicolon, or parentheses

77. [warning] design-no-em-dash-in-jsx-text — skills/budge/website/app/building-the-preview/page.tsx:150
   Em dash (—) in JSX text reads as model output — replace with comma, colon, semicolon, or parentheses

78. [warning] design-no-em-dash-in-jsx-text — skills/budge/website/app/building-the-preview/page.tsx:170
   Em dash (—) in JSX text reads as model output — replace with comma, colon, semicolon, or parentheses

79. [warning] design-no-em-dash-in-jsx-text — skills/budge/website/app/building-the-preview/page.tsx:181
   Em dash (—) in JSX text reads as model output — replace with comma, colon, semicolon, or parentheses

80. [warning] design-no-em-dash-in-jsx-text — skills/budge/website/app/building-the-preview/page.tsx:191
   Em dash (—) in JSX text reads as model output — replace with comma, colon, semicolon, or parentheses

81. [warning] no-giant-component — skills/budge/website/app/__budge.tsx:339
   Component "Budge" is 376 lines — consider breaking it into smaller focused components

82. [warning] prefer-useReducer — skills/budge/website/app/__budge.tsx:339
   Component "Budge" has 11 useState calls — consider useReducer for related state

83. [warning] rerender-state-only-in-handlers — skills/budge/website/app/__budge.tsx:352
   useState "targetEl" is updated but never read in the component's return — use useRef so updates don't trigger re-renders

84. [warning] rerender-state-only-in-handlers — skills/budge/website/app/__budge.tsx:354
   useState "dismissed" is updated but never read in the component's return — use useRef so updates don't trigger re-renders

85. [warning] rendering-hydration-no-flicker — skills/budge/website/app/__budge.tsx:415
   useEffect(setState, []) on mount causes a flash — consider useSyncExternalStore or suppressHydrationWarning

86. [warning] no-cascading-set-state — skills/budge/website/app/__budge.tsx:420
   5 setState calls in a single useEffect — consider using useReducer or deriving state

87. [warning] no-cascading-set-state — skills/budge/website/app/__budge.tsx:460
   6 setState calls in a single useEffect — consider using useReducer or deriving state

88. [warning] no-cascading-set-state — skills/budge/website/app/__budge.tsx:473
   3 setState calls in a single useEffect — consider using useReducer or deriving state

89. [warning] no-cascading-set-state — skills/budge/website/app/__budge.tsx:533
   18 setState calls in a single useEffect — consider using useReducer or deriving state

90. [warning] no-cascading-set-state — skills/budge/website/app/__budge.tsx:759
   3 setState calls in a single useEffect — consider using useReducer or deriving state

91. [warning] no-inline-exhaustive-style — skills/budge/website/app/__budge.tsx:1034
   17 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

92. [warning] no-z-index-9999 — skills/budge/website/app/__budge.tsx:1040
   z-index: 2147483647 is arbitrarily high — use a deliberate z-index scale (1–50). Extreme values signal a stacking context problem, not a fix

93. [warning] no-inline-exhaustive-style — skills/budge/website/app/__budge.tsx:1059
   10 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

94. [warning] no-inline-exhaustive-style — skills/budge/website/app/__budge.tsx:1085
   8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

95. [warning] no-inline-bounce-easing — skills/budge/website/app/__budge.tsx:1107
   Bounce/elastic easing feels dated — real objects decelerate smoothly. Use ease-out or cubic-bezier(0.16, 1, 0.3, 1) instead

96. [warning] no-inline-exhaustive-style — skills/budge/website/app/__budge.tsx:1132
   8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

97. [warning] no-tiny-text — skills/budge/website/app/__budge.tsx:1150
   Font size 11px is too small — body text should be at least 12px for readability, 16px is ideal

98. [warning] no-inline-exhaustive-style — skills/budge/website/app/__budge.tsx:1184
   14 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

99. [warning] no-z-index-9999 — skills/budge/website/app/__budge.tsx:1196
   z-index: 2147483647 is arbitrarily high — use a deliberate z-index scale (1–50). Extreme values signal a stacking context problem, not a fix

100. [warning] use-lazy-motion — skills/budge/website/components/ui/accordion.tsx:5
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

101. [warning] no-polymorphic-children — skills/budge/website/components/ui/accordion.tsx:113
   Polymorphic `typeof children === "string"` check — expose explicit subcomponents (e.g. `<Button.Text>`) instead of branching on what the consumer passed

102. [warning] no-react19-deprecated-apis — skills/budge/website/components/ui/toggle-group.tsx:64
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

103. [warning] no-giant-component — skills/budge/website/app/terms/page.tsx:8
   Component "TermsPage" is 350 lines — consider breaking it into smaller focused components

104. [warning] nextjs-missing-metadata — skills/budge/website/app/replay/page.tsx:1
   Page without metadata or generateMetadata export — hurts SEO

105. [warning] react-compiler-destructure-method — skills/budge/website/app/replay/page.tsx:82
   Destructure for clarity: `const { get } = useSearchParams()` then call `get(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on

106. [warning] react-compiler-destructure-method — skills/budge/website/app/replay/page.tsx:83
   Destructure for clarity: `const { get } = useSearchParams()` then call `get(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on

107. [warning] nextjs-no-client-side-redirect — skills/budge/website/app/replay/page.tsx:87
   router.replace() in useEffect — use redirect() from next/navigation or handle navigation in an event handler

108. [warning] react-compiler-destructure-method — skills/budge/website/app/replay/page.tsx:87
   Destructure for clarity: `const { replace } = useRouter()` then call `replace(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on

109. [warning] click-events-have-key-events — skills/budge/website/components/budge-me-paper-preview.tsx:869
   Enforce a clickable non-interactive element has at least one keyboard event listener.

110. [warning] no-static-element-interactions — skills/budge/website/components/budge-me-paper-preview.tsx:869
   Static HTML elements with event handlers require a role.

111. [warning] js-tosorted-immutable — skills/budge/website/components/budge-me-paper-preview.tsx:67
   [...array].sort() — use array.toSorted() for immutable sorting (ES2023)

112. [warning] no-giant-component — skills/budge/website/components/budge-me-paper-preview.tsx:370
   Component "BudgeMePaperPreview" is 945 lines — consider breaking it into smaller focused components

113. [warning] prefer-useReducer — skills/budge/website/components/budge-me-paper-preview.tsx:370
   Component "BudgeMePaperPreview" has 18 useState calls — consider useReducer for related state

114. [warning] no-cascading-set-state — skills/budge/website/components/budge-me-paper-preview.tsx:422
   6 setState calls in a single useEffect — consider using useReducer or deriving state

115. [warning] js-tosorted-immutable — skills/budge/website/components/budge-me-paper-preview.tsx:531
   [...array].sort() — use array.toSorted() for immutable sorting (ES2023)

116. [warning] no-cascading-set-state — skills/budge/website/components/budge-me-paper-preview.tsx:622
   25 setState calls in a single useEffect — consider using useReducer or deriving state

117. [warning] no-cascading-set-state — skills/budge/website/components/budge-me-paper-preview.tsx:716
   19 setState calls in a single useEffect — consider using useReducer or deriving state

118. [warning] async-defer-await — skills/budge/website/components/budge-me-paper-preview.tsx:743
   await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast

119. [warning] async-defer-await — skills/budge/website/components/budge-me-paper-preview.tsx:746
   await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast

120. [warning] async-defer-await — skills/budge/website/components/budge-me-paper-preview.tsx:772
   await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast

121. [warning] async-defer-await — skills/budge/website/components/budge-me-paper-preview.tsx:791
   await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast

122. [warning] async-defer-await — skills/budge/website/components/budge-me-paper-preview.tsx:766
   await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast

123. [warning] async-defer-await — skills/budge/website/components/budge-me-paper-preview.tsx:785
   await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast

124. [warning] no-inline-exhaustive-style — skills/budge/website/components/budge-me-paper-preview.tsx:827
   9 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

125. [warning] no-layout-transition-inline — skills/budge/website/components/budge-me-paper-preview.tsx:914
   Transitioning layout property "padding" causes layout thrash every frame — use transform and opacity instead

126. [warning] no-inline-exhaustive-style — skills/budge/website/components/budge-me-paper-preview.tsx:927
   8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

127. [warning] no-inline-exhaustive-style — skills/budge/website/components/budge-me-paper-preview.tsx:955
   14 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

128. [warning] no-inline-exhaustive-style — skills/budge/website/components/budge-me-paper-preview.tsx:978
   10 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

129. [warning] no-inline-exhaustive-style — skills/budge/website/components/budge-me-paper-preview.tsx:1003
   8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

130. [warning] no-inline-bounce-easing — skills/budge/website/components/budge-me-paper-preview.tsx:1026
   Bounce/elastic easing feels dated — real objects decelerate smoothly. Use ease-out or cubic-bezier(0.16, 1, 0.3, 1) instead

131. [warning] no-inline-exhaustive-style — skills/budge/website/components/budge-me-paper-preview.tsx:1052
   8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

132. [warning] no-tiny-text — skills/budge/website/components/budge-me-paper-preview.tsx:1069
   Font size 11px is too small — body text should be at least 12px for readability, 16px is ideal

133. [warning] no-inline-exhaustive-style — skills/budge/website/components/budge-me-paper-preview.tsx:1075
   10 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

134. [warning] no-tiny-text — skills/budge/website/components/budge-me-paper-preview.tsx:1079
   Font size 11px is too small — body text should be at least 12px for readability, 16px is ideal

135. [warning] no-inline-exhaustive-style — skills/budge/website/components/budge-me-paper-preview.tsx:1092
   8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

136. [warning] no-tiny-text — skills/budge/website/components/budge-me-paper-preview.tsx:1109
   Font size 11px is too small — body text should be at least 12px for readability, 16px is ideal

137. [warning] no-inline-exhaustive-style — skills/budge/website/components/budge-me-paper-preview.tsx:1115
   10 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

138. [warning] no-tiny-text — skills/budge/website/components/budge-me-paper-preview.tsx:1119
   Font size 11px is too small — body text should be at least 12px for readability, 16px is ideal

139. [warning] no-inline-exhaustive-style — skills/budge/website/components/budge-me-paper-preview.tsx:1161
   9 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

140. [warning] no-inline-exhaustive-style — skills/budge/website/components/budge-me-paper-preview.tsx:1207
   9 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

141. [warning] no-inline-exhaustive-style — skills/budge/website/components/budge-me-paper-preview.tsx:1257
   13 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse

142. [warning] no-autofocus — skills/budge/website/app/page.tsx:36
   The `autoFocus` attribute is found here, which can cause usability issues for sighted and non-sighted users.

143. [warning] nextjs-missing-metadata — skills/budge/website/app/page.tsx:6
   Page without metadata or generateMetadata export — hurts SEO

144. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:15
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

145. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:15
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

146. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:16
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

147. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:18
   array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups

148. [warning] js-cache-property-access — skills/budge/website/public/budge.iife.js:18
   t.memoizedProps.revealOrder is read 4 times inside this loop — hoist into a const at the top of the loop body

149. [warning] js-cache-property-access — skills/budge/website/public/budge.iife.js:19
   n.style.display is read 3 times inside this loop — hoist into a const at the top of the loop body

150. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:22
   array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups

151. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:25
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

152. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:25
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

153. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:25
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

154. [warning] js-combine-iterations — skills/budge/website/public/budge.iife.js:28
   .map().filter() iterates the array twice — combine into a single loop with .reduce() or for...of

155. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:46
   array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups

156. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:63
   array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups

157. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:82
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

158. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:82
   array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups

159. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:82
   array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups

160. [warning] js-hoist-intl — skills/budge/website/public/budge.iife.js:82
   new Intl.Segmenter() inside a function — hoist to module scope or wrap in useMemo so it isn't recreated each call

161. [warning] js-flatmap-filter — skills/budge/website/public/budge.iife.js:82
   .map().filter(Boolean) iterates twice — use .flatMap() to transform and filter in a single pass

162. [warning] js-set-map-lookups — skills/budge/website/public/budge.iife.js:83
   array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups

163. [warning] js-flatmap-filter — skills/budge/website/public/budge.iife.js:84
   .map().filter(Boolean) iterates twice — use .flatMap() to transform and filter in a single pass

164. [warning] async-defer-await — skills/budge/website/public/budge.iife.js:84
   await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast

165. [warning] click-events-have-key-events — skills/budge/website/components/replay/replay-viewer.tsx:1097
   Enforce a clickable non-interactive element has at least one keyboard event listener.

166. [warning] no-static-element-interactions — skills/budge/website/components/replay/replay-viewer.tsx:1097
   Static HTML elements with event handlers require a role.

167. [warning] use-lazy-motion — skills/budge/website/components/replay/replay-viewer.tsx:7
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

168. [warning] no-giant-component — skills/budge/website/components/replay/replay-viewer.tsx:339
   Component "ReplayViewer" is 1002 lines — consider breaking it into smaller focused components

169. [warning] prefer-useReducer — skills/budge/website/components/replay/replay-viewer.tsx:345
   Component "ReplayViewer" has 5 useState calls — consider useReducer for related state

170. [warning] js-batch-dom-css — skills/budge/website/components/replay/replay-viewer.tsx:600
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

171. [warning] js-batch-dom-css — skills/budge/website/components/replay/replay-viewer.tsx:601
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

172. [warning] js-batch-dom-css — skills/budge/website/components/replay/replay-viewer.tsx:602
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

173. [warning] js-batch-dom-css — skills/budge/website/components/replay/replay-viewer.tsx:603
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

174. [warning] js-batch-dom-css — skills/budge/website/components/replay/replay-viewer.tsx:604
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

175. [warning] js-batch-dom-css — skills/budge/website/components/replay/replay-viewer.tsx:605
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

176. [warning] design-no-three-period-ellipsis — skills/budge/website/components/replay/replay-viewer.tsx:1136
   Three-period ellipsis ("...") in JSX text — use the actual ellipsis character "…" (or `&hellip;`)

177. [warning] design-no-three-period-ellipsis — skills/budge/website/components/replay/replay-viewer.tsx:1155
   Three-period ellipsis ("...") in JSX text — use the actual ellipsis character "…" (or `&hellip;`)

178. [warning] prefer-use-effect-event — skills/budge/website/components/budge-logo.tsx:85
   "scheduleNext" is read only inside `setTimeout` — wrap it with useEffectEvent and remove it from the dep array so the effect doesn't re-synchronize on every parent render

179. [warning] no-cascading-set-state — skills/budge/website/components/budge-logo.tsx:62
   8 setState calls in a single useEffect — consider using useReducer or deriving state

180. [warning] nextjs-missing-metadata — skills/grug/website/app/page.tsx:1
   Page without metadata or generateMetadata export — hurts SEO

181. [warning] prefer-use-effect-event — skills/grug/website/components/grug-logo.tsx:49
   "scheduleNext" is read only inside `setTimeout` — wrap it with useEffectEvent and remove it from the dep array so the effect doesn't re-synchronize on every parent render

182. [warning] no-cascading-set-state — skills/grug/website/components/grug-logo.tsx:29
   6 setState calls in a single useEffect — consider using useReducer or deriving state

183. [warning] no-cascading-set-state — skills/grug/website/components/grug-demo.tsx:48
   12 setState calls in a single useEffect — consider using useReducer or deriving state

❌ Errors (40)

React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render. · 36 in 2 files

rules-of-hooks

Move the Hook call before the condition, or call it unconditionally and branch inside the Hook/effect instead.

File Lines
skills/budge/website/app/__budge.tsx 342, 351, 352, 353, 354, 355, 356, 357, +27 more
skills/budge/website/public/budge.iife.js 82
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(...) · 2 in 1 file

effect-needs-cleanup

Return a cleanup function that releases the subscription / timer: return () =&gt; target.removeEventListener(name, handler) for listeners, return () =&gt; clearInterval(id) / clearTimeout(id) for timers, or return unsubscribe if the subscribe call already returned one

File Lines
skills/budge/website/components/budge-me-paper-preview.tsx 422, 716
Project uses a motion library but has no prefers-reduced-motion handling — required for accessibility (WCAG 2.3.3) · 1 in 1 file

require-reduced-motion

Add useReducedMotion() from your animation library, or a @media (prefers-reduced-motion: reduce) CSS query

File Lines
skills/budge/budge/package.json 0
Component "C" defined inside "Zu" — creates new instance every render, destroying state · 1 in 1 file

no-nested-component-definition

Move to a separate file or to module scope above the parent component

File Lines
skills/budge/website/public/budge.iife.js 82

⚠️ Warnings (143)

14 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse · 24 in 3 files

no-inline-exhaustive-style

Move styles to a CSS class, CSS module, Tailwind utilities, or a styled component — inline objects with many properties hurt readability and create new references every render

File Lines
skills/budge/website/components/budge-me-paper-preview.tsx 827, 927, 955, 978, 1003, 1052, 1075, 1092, +4 more
skills/budge/budge/src/budge.tsx 1041, 1064, 1089, 1138, 1161, 1178, 1201
skills/budge/website/app/__budge.tsx 1034, 1059, 1085, 1132, 1184
array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups · 14 in 1 file

js-set-map-lookups

Use a Set or Map for repeated membership tests / keyed lookups — Array.includes/find is O(n) per call

File Lines
skills/budge/website/public/budge.iife.js 15, 15, 16, 18, 22, 25, 25, 25, +6 more
8 setState calls in a single useEffect — consider using useReducer or deriving state · 13 in 6 files

no-cascading-set-state

Combine into useReducer: const [state, dispatch] = useReducer(reducer, initialState)

File Lines
skills/budge/website/app/__budge.tsx 420, 460, 473, 533, 759
skills/budge/website/components/budge-me-paper-preview.tsx 422, 622, 716
skills/budge/budge/src/budge.tsx 529, 870
skills/budge/website/components/budge-logo.tsx 62
skills/grug/website/components/grug-logo.tsx 29
…and 1 more file view on react.review
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows · 12 in 2 files

js-batch-dom-css

Batch DOM/CSS reads and writes — interleaving them inside a loop causes layout thrashing. Read first, then write

File Lines
skills/budge/budge/src/entry.tsx 240, 241, 242, 243, 244, 245
skills/budge/website/components/replay/replay-viewer.tsx 600, 601, 602, 603, 604, 605
Font size 11px is too small — body text should be at least 12px for readability, 16px is ideal · 9 in 3 files

no-tiny-text

Use at least 12px for body content, 16px is ideal. Small text is hard to read, especially on high-DPI mobile screens

File Lines
skills/budge/budge/src/budge.tsx 1155, 1165, 1195, 1205
skills/budge/website/components/budge-me-paper-preview.tsx 1069, 1079, 1109, 1119
skills/budge/website/app/__budge.tsx 1150
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast · 8 in 3 files

async-defer-await

Move the await after the synchronous early-return guard so the skip path stays fast

File Lines
skills/budge/website/components/budge-me-paper-preview.tsx 743, 746, 766, 772, 785, 791
skills/budge/budge/src/entry.tsx 680
skills/budge/website/public/budge.iife.js 84
Em dash (—) in JSX text reads as model output — replace with comma, colon, semicolon, or parentheses · 8 in 1 file

design-no-em-dash-in-jsx-text

Replace em dashes in JSX prose with commas, colons, semicolons, or parentheses so UI copy reads less like generated text.

File Lines
skills/budge/website/app/building-the-preview/page.tsx 108, 119, 128, 137, 150, 170, 181, 191
Component "Budge" is 800 lines — consider breaking it into smaller focused components · 5 in 5 files

no-giant-component

Extract logical sections into focused components: &lt;UserHeader /&gt;, &lt;UserActions /&gt;, etc.

File Lines
skills/budge/budge/src/budge.tsx 446
skills/budge/website/app/__budge.tsx 339
skills/budge/website/app/terms/page.tsx 8
skills/budge/website/components/budge-me-paper-preview.tsx 370
skills/budge/website/components/replay/replay-viewer.tsx 339
.map().filter(Boolean) iterates twice — use .flatMap() to transform and filter in a single pass · 4 in 3 files

js-flatmap-filter

Use .flatMap(item =&gt; condition ? [value] : []) — transforms and filters in a single pass instead of creating an intermediate array

File Lines
skills/budge/website/public/budge.iife.js 82, 84
skills/budge/budge/src/entry.tsx 429
skills/budge/budge/src/budge.tsx 109
Component "Budge" has 19 useState calls — consider useReducer for related state · 4 in 4 files

prefer-useReducer

Group related state: const [state, dispatch] = useReducer(reducer, { field1, field2, ... })

File Lines
skills/budge/budge/src/budge.tsx 446
skills/budge/website/app/__budge.tsx 339
skills/budge/website/components/budge-me-paper-preview.tsx 370
skills/budge/website/components/replay/replay-viewer.tsx 345
useState "showPrompt" is updated but never read in the component's return — use useRef so updates don't trigger re-renders · 4 in 2 files

rerender-state-only-in-handlers

Replace useState with useRef when the value is only mutated and never read in render — ref.current = ... updates without re-rendering the component

File Lines
skills/budge/budge/src/budge.tsx 457, 458
skills/budge/website/app/__budge.tsx 352, 354
Page without metadata or generateMetadata export — hurts SEO · 4 in 4 files

nextjs-missing-metadata

Add export const metadata = { title: '...', description: '...' } or export async function generateMetadata()

File Lines
skills/budge/website/app/building-the-preview/page.tsx 1
skills/budge/website/app/replay/page.tsx 1
skills/budge/website/app/page.tsx 6
skills/grug/website/app/page.tsx 1
z-index: 2147483646 is arbitrarily high — use a deliberate z-index scale (1–50). Extreme values signal a stacking context problem, not a fix · 3 in 2 files

no-z-index-9999

Define a z-index scale in your design tokens (e.g. dropdown: 10, modal: 20, toast: 30). Create a new stacking context with isolation: isolate instead of escalating values

File Lines
skills/budge/website/app/__budge.tsx 1040, 1196
skills/budge/budge/src/budge.tsx 1032
Bounce/elastic easing feels dated — real objects decelerate smoothly. Use ease-out or cubic-bezier(0.16, 1, 0.3, 1) instead · 3 in 3 files

no-inline-bounce-easing

Use cubic-bezier(0.16, 1, 0.3, 1) (ease-out-expo) for natural deceleration — objects in the real world don't bounce

File Lines
skills/budge/budge/src/budge.tsx 1112
skills/budge/website/app/__budge.tsx 1107
skills/budge/website/components/budge-me-paper-preview.tsx 1026
Destructure for clarity: `const { get } = useSearchParams()` then call `get(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on · 3 in 1 file

react-compiler-destructure-method

Destructure the method up front: const { push } = useRouter() then call push(...) directly — clearer dependency graph and easier for React Compiler to memoize

File Lines
skills/budge/website/app/replay/page.tsx 82, 83, 87
Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size · 2 in 2 files

use-lazy-motion

Use import { LazyMotion, m } from "framer-motion" with domAnimation features — saves ~30kb

File Lines
skills/budge/website/components/ui/accordion.tsx 5
skills/budge/website/components/replay/replay-viewer.tsx 7
Enforce a clickable non-interactive element has at least one keyboard event listener. · 2 in 2 files

click-events-have-key-events

Visible, non-interactive elements with click handlers must have one of keyup, keydown, or keypress listener.

File Lines
skills/budge/website/components/budge-me-paper-preview.tsx 869
skills/budge/website/components/replay/replay-viewer.tsx 1097
Static HTML elements with event handlers require a role. · 2 in 2 files

no-static-element-interactions

Add a role attribute to this element, or use a semantic HTML element instead.

File Lines
skills/budge/website/components/budge-me-paper-preview.tsx 869
skills/budge/website/components/replay/replay-viewer.tsx 1097
[...array].sort() — use array.toSorted() for immutable sorting (ES2023) · 2 in 1 file

js-tosorted-immutable

Use array.toSorted() (ES2023) instead of [...array].sort() for immutable sorting without the spread allocation

File Lines
skills/budge/website/components/budge-me-paper-preview.tsx 67, 531
t.memoizedProps.revealOrder is read 4 times inside this loop — hoist into a const at the top of the loop body · 2 in 1 file

js-cache-property-access

Hoist the deep member access into a const at the top of the loop body: const { x, y } = obj.deeply.nested

File Lines
skills/budge/website/public/budge.iife.js 18, 19
Three-period ellipsis ("...") in JSX text — use the actual ellipsis character "…" (or `…`) · 2 in 1 file

design-no-three-period-ellipsis

Use the typographic ellipsis "…" (or &hellip;) instead of three periods — pairs with action-with-followup labels ("Rename…", "Loading…")

File Lines
skills/budge/website/components/replay/replay-viewer.tsx 1136, 1155
"scheduleNext" is read only inside `setTimeout` — wrap it with useEffectEvent and remove it from the dep array so the effect doesn't re-synchronize on every parent render · 2 in 2 files

prefer-use-effect-event

Wrap the callback with useEffectEvent(callback) (React 19+) and call the resulting binding from inside the sub-handler. The Effect Event captures the latest props/state without being a reactive dep, so the effect doesn't re-subscribe on every parent render. See https://react.dev/reference/react/useEffectEvent

File Lines
skills/budge/website/components/budge-logo.tsx 85
skills/grug/website/components/grug-logo.tsx 49
outline: none removes keyboard focus visibility — use :focus-visible styling instead, or provide a box-shadow focus ring · 1 in 1 file

no-outline-none

Use :focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px } to show focus only for keyboard users while hiding it for mouse clicks

File Lines
skills/budge/budge/src/budge.tsx 1032
Array index "index" used as key — causes bugs when list is reordered or filtered · 1 in 1 file

no-array-index-as-key

Use a stable unique identifier: key={item.id} or key={item.slug} — index keys break on reorder/filter

File Lines
skills/budge/website/app/claude-spinner.tsx 42
Use next/link instead of <a> for internal links — enables client-side navigation and prefetching · 1 in 1 file

nextjs-no-a-element

import Link from 'next/link' — enables client-side navigation, prefetching, and preserves scroll position

File Lines
skills/budge/website/app/building-the-preview/page.tsx 99
useEffect(setState, []) on mount causes a flash — consider useSyncExternalStore or suppressHydrationWarning · 1 in 1 file

rendering-hydration-no-flicker

Use useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) or add suppressHydrationWarning to the element

File Lines
skills/budge/website/app/__budge.tsx 415
Polymorphic `typeof children === "string"` check — expose explicit subcomponents (e.g. `<Button.Text>`) instead of branching on what the consumer passed · 1 in 1 file

no-polymorphic-children

Expose explicit subcomponents (&lt;Button.Text&gt;, &lt;Button.Icon&gt;) so consumers don't need to switch on typeof children

File Lines
skills/budge/website/components/ui/accordion.tsx 113
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'` · 1 in 1 file

no-react19-deprecated-apis

Pass ref as a regular prop on function components — forwardRef is no longer needed in React 19+. Replace useContext(X) with use(X) for branch-aware context reads. Only enabled on projects detected as React 19+.

File Lines
skills/budge/website/components/ui/toggle-group.tsx 64
router.replace() in useEffect — use redirect() from next/navigation or handle navigation in an event handler · 1 in 1 file

nextjs-no-client-side-redirect

Avoid redirects inside useEffect. Use an event handler, middleware, or server-side redirect (App Router: redirect() from next/navigation; Pages Router: getServerSideProps redirect)

File Lines
skills/budge/website/app/replay/page.tsx 87
Transitioning layout property "padding" causes layout thrash every frame — use transform and opacity instead · 1 in 1 file

no-layout-transition-inline

Use transform and opacity for transitions — they run on the compositor thread. For height animations, use grid-template-rows: 0fr → 1fr

File Lines
skills/budge/website/components/budge-me-paper-preview.tsx 914
The `autoFocus` attribute is found here, which can cause usability issues for sighted and non-sighted users. · 1 in 1 file

no-autofocus

Remove the autoFocus attribute.

File Lines
skills/budge/website/app/page.tsx 36
.map().filter() iterates the array twice — combine into a single loop with .reduce() or for...of · 1 in 1 file

js-combine-iterations

Combine .map().filter() (or similar chains) into a single pass with .reduce() or a for...of loop to avoid iterating the array twice

File Lines
skills/budge/website/public/budge.iife.js 28
new Intl.Segmenter() inside a function — hoist to module scope or wrap in useMemo so it isn't recreated each call · 1 in 1 file

js-hoist-intl

Hoist new Intl.NumberFormat(...) to module scope or wrap in useMemo — Intl constructors allocate dozens of objects per lo


Issue body truncated. See the full report at react.review/dashboard.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions