Skip to content

React Review Audit #1

Description

@react-doctor
⚠️ 94 warnings 87 score
Copy as prompt
Fix the following React Review diagnostics in my codebase.

## Warnings (94)

1. [warning] rerender-functional-setstate — src/components/ApiSettings.tsx:30
   setLocalConfig({ ...localConfig, ... }) — use functional update `setLocalConfig(prev => ({ ...prev, ... }))` to avoid stale closures

2. [warning] rerender-functional-setstate — src/components/ApiSettings.tsx:38
   setLocalConfig({ ...localConfig, ... }) — use functional update `setLocalConfig(prev => ({ ...prev, ... }))` to avoid stale closures

3. [warning] rerender-functional-setstate — src/components/ApiSettings.tsx:102
   setLocalConfig({ ...localConfig, ... }) — use functional update `setLocalConfig(prev => ({ ...prev, ... }))` to avoid stale closures

4. [warning] rerender-functional-setstate — src/components/ApiSettings.tsx:117
   setLocalConfig({ ...localConfig, ... }) — use functional update `setLocalConfig(prev => ({ ...prev, ... }))` to avoid stale closures

5. [warning] no-giant-component — src/App.tsx:33
   Component "App" is 515 lines — consider breaking it into smaller focused components

6. [warning] prefer-useReducer — src/App.tsx:33
   Component "App" has 19 useState calls — consider useReducer for related state

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

8. [warning] async-defer-await — src/App.tsx:138
   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

9. [warning] async-defer-await — src/App.tsx:142
   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

10. [warning] async-defer-await — src/App.tsx:220
   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

11. [warning] no-cascading-set-state — src/App.tsx:244
   3 setState calls in a single useEffect — consider using useReducer or deriving state

12. [warning] no-generic-handler-names — src/components/UploadZone.tsx:71
   Non-descriptive handler name "handleClick" — name should describe what it does, not when it runs

13. [warning] no-inline-bounce-easing — src/components/UploadZone.tsx:82
   animate-bounce feels dated and tacky — use a subtle ease-out transform for natural deceleration

14. [warning] async-defer-await — src/hooks/usePdfSearch.ts:143
   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

15. [warning] async-defer-await — src/hooks/usePdfSearch.ts:157
   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

16. [warning] async-defer-await — src/hooks/usePdfSearch.ts:165
   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

17. [warning] async-defer-await — src/hooks/usePdfSearch.ts:177
   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

18. [warning] async-await-in-loop — src/hooks/usePdfSearch.ts:143
   await inside a for-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

19. [warning] async-await-in-loop — src/hooks/usePdfSearch.ts:165
   await inside a for-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

20. [warning] no-react19-deprecated-apis — src/components/ui/scroll-area.tsx:5
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

21. [warning] no-giant-component — src/components/PdfToolbar.tsx:87
   Component "PdfToolbarComponent" is 394 lines — consider breaking it into smaller focused components

22. [warning] no-many-boolean-props — src/components/PdfToolbar.tsx:87
   Component "PdfToolbarComponent" takes 4 boolean-like props (isSearchOpen, isSearching, isSettingsOpen…) — consider compound components or explicit variants instead of stacking flags

23. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:133
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

24. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:137
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

25. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:143
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

26. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:147
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

27. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:158
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

28. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:163
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

29. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:189
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

30. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:194
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

31. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:205
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

32. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:209
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

33. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:217
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

34. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:221
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

35. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:226
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

36. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:231
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

37. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:233
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

38. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:305
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

39. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:310
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

40. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:316
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

41. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:321
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

42. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:328
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

43. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:355
   w-3.5 h-3.5 → use the shorthand size-3.5 (Tailwind v3.4+)

44. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:371
   w-7 h-7 → use the shorthand size-7 (Tailwind v3.4+)

45. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:376
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

46. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:381
   w-7 h-7 → use the shorthand size-7 (Tailwind v3.4+)

47. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:386
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

48. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:441
   w-7 h-7 → use the shorthand size-7 (Tailwind v3.4+)

49. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:445
   w-3.5 h-3.5 → use the shorthand size-3.5 (Tailwind v3.4+)

50. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:453
   w-7 h-7 → use the shorthand size-7 (Tailwind v3.4+)

51. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:457
   w-3.5 h-3.5 → use the shorthand size-3.5 (Tailwind v3.4+)

52. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:463
   w-9 h-9 → use the shorthand size-9 (Tailwind v3.4+)

53. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:468
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

54. [warning] design-no-redundant-size-axes — src/components/PdfToolbar.tsx:470
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

55. [warning] no-inline-bounce-easing — src/components/ChatPanel.tsx:42
   animate-bounce feels dated and tacky — use a subtle ease-out transform for natural deceleration

56. [warning] no-inline-bounce-easing — src/components/ChatPanel.tsx:46
   animate-bounce feels dated and tacky — use a subtle ease-out transform for natural deceleration

57. [warning] no-inline-bounce-easing — src/components/ChatPanel.tsx:50
   animate-bounce feels dated and tacky — use a subtle ease-out transform for natural deceleration

58. [warning] no-giant-component — src/components/ChatPanel.tsx:82
   Component "ChatPanel" is 333 lines — consider breaking it into smaller focused components

59. [warning] design-no-redundant-size-axes — src/components/ChatPanel.tsx:180
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

60. [warning] design-no-redundant-size-axes — src/components/ChatPanel.tsx:191
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

61. [warning] design-no-redundant-size-axes — src/components/ChatPanel.tsx:201
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

62. [warning] design-no-redundant-size-axes — src/components/ChatPanel.tsx:211
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

63. [warning] js-batch-dom-css — src/components/ChatPanel.tsx:385
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

64. [warning] rendering-usetransition-loading — src/hooks/useChat.ts:55
   useState for "isLoading" — if this guards a state transition (not an async fetch), consider useTransition instead

65. [warning] async-await-in-loop — src/hooks/useChat.ts:151
   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

66. [warning] rerender-state-only-in-handlers — src/components/TextSelectionPopup.tsx:34
   useState "selectedText" is updated but never read in the component's return — use useRef so updates don't trigger re-renders

67. [warning] advanced-event-handler-refs — src/components/TextSelectionPopup.tsx:132
   useEffect re-subscribes a "handleMouseUp" listener every time the handler identity changes — store the handler in a ref and have the listener read `handlerRef.current()`, then drop it from the deps

68. [warning] design-no-redundant-size-axes — src/components/TextSelectionPopup.tsx:184
   w-3.5 h-3.5 → use the shorthand size-3.5 (Tailwind v3.4+)

69. [warning] design-no-redundant-size-axes — src/components/TextSelectionPopup.tsx:197
   w-3.5 h-3.5 → use the shorthand size-3.5 (Tailwind v3.4+)

70. [warning] design-no-redundant-size-axes — src/components/PdfSidebar.tsx:159
   w-3.5 h-3.5 → use the shorthand size-3.5 (Tailwind v3.4+)

71. [warning] design-no-redundant-size-axes — src/components/PdfSidebar.tsx:161
   w-3.5 h-3.5 → use the shorthand size-3.5 (Tailwind v3.4+)

72. [warning] design-no-redundant-size-axes — src/components/PdfSidebar.tsx:181
   w-3 h-3 → use the shorthand size-3 (Tailwind v3.4+)

73. [warning] design-no-redundant-size-axes — src/components/PdfSidebar.tsx:370
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

74. [warning] design-no-redundant-size-axes — src/components/PdfSidebar.tsx:374
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

75. [warning] design-no-redundant-size-axes — src/components/PdfSidebar.tsx:402
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

76. [warning] no-giant-component — src/components/PdfViewer.tsx:97
   Component "PdfViewer" is 1002 lines — consider breaking it into smaller focused components

77. [warning] prefer-useReducer — src/components/PdfViewer.tsx:108
   Component "PdfViewer" has 25 useState calls — consider useReducer for related state

78. [warning] rerender-state-only-in-handlers — src/components/PdfViewer.tsx:136
   useState "outlinePageMap" is updated but never read in the component's return — use useRef so updates don't trigger re-renders

79. [warning] rerender-state-only-in-handlers — src/components/PdfViewer.tsx:137
   useState "thumbnailAnchor" is updated but never read in the component's return — use useRef so updates don't trigger re-renders

80. [warning] rendering-usetransition-loading — src/components/PdfViewer.tsx:116
   useState for "isLoading" — if this guards a state transition (not an async fetch), consider useTransition instead

81. [warning] no-derived-useState — src/components/PdfViewer.tsx:150
   useState initialized from prop "initialAutoFollow" — if this value should stay in sync with the prop, derive it during render instead

82. [warning] no-derived-useState — src/components/PdfViewer.tsx:151
   useState initialized from prop "initialContextWindow" — if this value should stay in sync with the prop, derive it during render instead

83. [warning] no-prop-callback-in-effect — src/components/PdfViewer.tsx:576
   useEffect calls prop callback "onCurrentPageChange" with local state in deps — this is the "lift state via callback" anti-pattern; lift state into a shared Provider so both sides read the same source

84. [warning] no-prop-callback-in-effect — src/components/PdfViewer.tsx:593
   useEffect calls prop callback "onPageRangeChange" with local state in deps — this is the "lift state via callback" anti-pattern; lift state into a shared Provider so both sides read the same source

85. [warning] no-cascading-set-state — src/components/PdfViewer.tsx:641
   3 setState calls in a single useEffect — consider using useReducer or deriving state

86. [warning] no-cascading-set-state — src/components/PdfViewer.tsx:664
   25 setState calls in a single useEffect — consider using useReducer or deriving state

87. [warning] no-cascading-set-state — src/components/PdfViewer.tsx:711
   8 setState calls in a single useEffect — consider using useReducer or deriving state

88. [warning] async-defer-await — src/components/PdfViewer.tsx:721
   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

89. [warning] async-defer-await — src/components/PdfViewer.tsx:735
   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

90. [warning] async-defer-await — src/components/PdfViewer.tsx:776
   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

91. [warning] design-no-redundant-size-axes — src/components/PdfViewer.tsx:1022
   w-10 h-10 → use the shorthand size-10 (Tailwind v3.4+)

92. [warning] design-no-redundant-size-axes — src/components/PdfViewer.tsx:1049
   w-10 h-10 → use the shorthand size-10 (Tailwind v3.4+)

93. [warning] design-no-redundant-size-axes — src/components/PdfViewer.tsx:1068
   w-12 h-12 → use the shorthand size-12 (Tailwind v3.4+)

94. [warning] design-no-redundant-size-axes — src/components/PdfViewer.tsx:1079
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

⚠️ Warnings (94)

w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+) · 48 in 5 files

design-no-redundant-size-axes

Collapse w-N h-N to size-N (Tailwind v3.4+) when both axes match

File Lines
src/components/PdfToolbar.tsx 133, 137, 143, 147, 158, 163, 189, 194, +24 more
src/components/PdfSidebar.tsx 159, 161, 181, 370, 374, 402
src/components/ChatPanel.tsx 180, 191, 201, 211
src/components/PdfViewer.tsx 1022, 1049, 1068, 1079
src/components/TextSelectionPopup.tsx 184, 197
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 · 10 in 3 files

async-defer-await

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

File Lines
src/hooks/usePdfSearch.ts 143, 157, 165, 177
src/App.tsx 138, 142, 220
src/components/PdfViewer.tsx 721, 735, 776
setLocalConfig({ ...localConfig, ... }) — use functional update `setLocalConfig(prev => ({ ...prev, ... }))` to avoid stale closures · 4 in 1 file

rerender-functional-setstate

Use the callback form: setState(prev => prev + 1) to always read the latest value

File Lines
src/components/ApiSettings.tsx 30, 38, 102, 117
Component "App" is 515 lines — consider breaking it into smaller focused components · 4 in 4 files

no-giant-component

Extract logical sections into focused components: <UserHeader />, <UserActions />, etc.

File Lines
src/App.tsx 33
src/components/PdfToolbar.tsx 87
src/components/ChatPanel.tsx 82
src/components/PdfViewer.tsx 97
useState "outline" is updated but never read in the component's return — use useRef so updates don't trigger re-renders · 4 in 3 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
src/components/PdfViewer.tsx 136, 137
src/App.tsx 42
src/components/TextSelectionPopup.tsx 34
3 setState calls in a single useEffect — consider using useReducer or deriving state · 4 in 2 files

no-cascading-set-state

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

File Lines
src/components/PdfViewer.tsx 641, 664, 711
src/App.tsx 244
animate-bounce feels dated and tacky — use a subtle ease-out transform for natural deceleration · 4 in 2 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
src/components/ChatPanel.tsx 42, 46, 50
src/components/UploadZone.tsx 82
await inside a for-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently · 3 in 2 files

async-await-in-loop

Collect the items and use await Promise.all(items.map(...)) to run independent operations concurrently

File Lines
src/hooks/usePdfSearch.ts 143, 165
src/hooks/useChat.ts 151
Component "App" has 19 useState calls — consider useReducer for related state · 2 in 2 files

prefer-useReducer

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

File Lines
src/App.tsx 33
src/components/PdfViewer.tsx 108
useState for "isLoading" — if this guards a state transition (not an async fetch), consider useTransition instead · 2 in 2 files

rendering-usetransition-loading

Replace with const [isPending, startTransition] = useTransition() — avoids a re-render for the loading state

File Lines
src/hooks/useChat.ts 55
src/components/PdfViewer.tsx 116
useState initialized from prop "initialAutoFollow" — if this value should stay in sync with the prop, derive it during render instead · 2 in 1 file

no-derived-useState

Remove useState and compute the value inline: const value = transform(propName)

File Lines
src/components/PdfViewer.tsx 150, 151
useEffect calls prop callback "onCurrentPageChange" with local state in deps — this is the "lift state via callback" anti-pattern; lift state into a shared Provider so both sides read the same source · 2 in 1 file

no-prop-callback-in-effect

Lift the shared state into a Provider so both sides read the same source — no useEffect-driven sync needed

File Lines
src/components/PdfViewer.tsx 576, 593
Non-descriptive handler name "handleClick" — name should describe what it does, not when it runs · 1 in 1 file

no-generic-handler-names

Rename to describe the action: e.g. handleSubmitsaveUserProfile, handleClicktoggleSidebar

File Lines
src/components/UploadZone.tsx 71
forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly · 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
src/components/ui/scroll-area.tsx 5
Component "PdfToolbarComponent" takes 4 boolean-like props (isSearchOpen, isSearching, isSettingsOpen…) — consider compound components or explicit variants instead of stacking flags · 1 in 1 file

no-many-boolean-props

Split into compound components or named variants: <Button.Primary />, <DialogConfirm /> instead of stacking isPrimary, isConfirm flags

File Lines
src/components/PdfToolbar.tsx 87
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows · 1 in 1 file

js-batch-dom-css

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

File Lines
src/components/ChatPanel.tsx 385
useEffect re-subscribes a "handleMouseUp" listener every time the handler identity changes — store the handler in a ref and have the listener read `handlerRef.current()`, then drop it from the deps · 1 in 1 file

advanced-event-handler-refs

Store the handler in a ref and have the listener read handlerRef.current() — the subscription stays put while the latest handler is always called

File Lines
src/components/TextSelectionPopup.tsx 132

Reviewed by reactreview for commit 714e0c3. Configure here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions