[Task] GRC-02 프런트엔드 lint debt 1차 정리#5
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/shared/hooks/use-throttle.ts (1)
17-39:⚠️ Potential issue | 🟡 MinorPotential stale closure: pending RAF may invoke outdated callback.
When
callbackchanges,useCallbackcreates a new throttled function, but any RAF already scheduled (line 33-37) still captures the oldcallbackreference. The cleanup effect only runs on unmount (empty deps), not whencallbackchanges, so the stale callback could be invoked.Consider using a ref to always call the latest callback:
🛡️ Proposed fix using a callback ref
import { useCallback, useEffect, useRef } from 'react' export function useThrottledCallback<TArgs extends unknown[]>( callback: (...args: TArgs) => void, delay: number = 16 ): (...args: TArgs) => void { const lastCallRef = useRef<number>(0) const rafRef = useRef<number | null>(null) + const callbackRef = useRef(callback) + + // Keep callback ref fresh so RAF always calls latest version + callbackRef.current = callback useEffect(() => { return () => { if (rafRef.current !== null) { cancelAnimationFrame(rafRef.current) } } }, []) - return useCallback((...args: TArgs) => { + return useCallback((...args: TArgs) => { const now = performance.now() if (now - lastCallRef.current >= delay) { lastCallRef.current = now - callback(...args) + callbackRef.current(...args) } else if (!rafRef.current) { rafRef.current = requestAnimationFrame(() => { lastCallRef.current = performance.now() rafRef.current = null - callback(...args) + callbackRef.current(...args) }) } - }, [callback, delay]) + }, [delay]) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/hooks/use-throttle.ts` around lines 17 - 39, The scheduled RAF can call a stale callback when `callback` changes; introduce a mutable ref (e.g., `callbackRef`) and update `callbackRef.current = callback` in a small effect that runs on `[callback]`, then invoke `callbackRef.current(...args)` everywhere (both in the immediate path and inside the `requestAnimationFrame` handler) instead of using the `callback` closed over by `useCallback`; keep `rafRef`, `lastCallRef`, and the existing unmount cleanup that cancels with `cancelAnimationFrame(rafRef.current)` but remove `callback` from the `useCallback` deps so the throttled function doesn’t recreate on each callback change.
🧹 Nitpick comments (2)
src/features/user/components/badge-generator.tsx (1)
19-46: Good refactor: extractingBadgeCopyButtonas a static component.This correctly addresses the lint warning by moving the component outside the parent, avoiding re-creation on each render.
Minor type refinement: The
typeprop acceptsCopyType(which includesnull), but the buttons always pass a specific type. Consider narrowing this for better type safety:🔧 Optional type refinement
type CopyType = "markdown" | "html" | "link" | null +type BadgeCopyType = Exclude<CopyType, null> + interface BadgeCopyButtonProps { copied: CopyType icon: LucideIcon label: string onCopy: () => void - type: CopyType + type: BadgeCopyType }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/user/components/badge-generator.tsx` around lines 19 - 46, The BadgeCopyButtonProps currently types the prop `type` as CopyType (which can be null) but every caller passes a concrete copy identifier; update the prop to a non-nullable variant (e.g., use NonNullable<CopyType> or Exclude<CopyType, null>) so `BadgeCopyButton`'s `type` cannot be null and improves type safety; adjust the BadgeCopyButtonProps declaration (and any related usages if necessary) to use the narrowed type while keeping `copied: CopyType` as-is.src/shared/components/ui/heatmap-background.tsx (1)
14-21: Consider throttling resize events to avoid excessive re-renders.The
resizeevent fires rapidly during window resizing. Each event triggersuseSyncExternalStoreto callgetSnapshot, and if the width changes,buildBlocksrecomputes all block properties. For a decorative background, this frequency may cause performance degradation on lower-end devices.♻️ Throttled resize subscription
function subscribeToWindowResize(onStoreChange: () => void) { if (typeof window === "undefined") { return () => {} } - window.addEventListener("resize", onStoreChange) - return () => window.removeEventListener("resize", onStoreChange) + let timeoutId: ReturnType<typeof setTimeout> | null = null + const throttledHandler = () => { + if (timeoutId) return + timeoutId = setTimeout(() => { + timeoutId = null + onStoreChange() + }, 100) + } + + window.addEventListener("resize", throttledHandler) + return () => { + window.removeEventListener("resize", throttledHandler) + if (timeoutId) clearTimeout(timeoutId) + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/components/ui/heatmap-background.tsx` around lines 14 - 21, The resize subscription currently calls onStoreChange for every resize event; throttle it to reduce re-renders by wrapping the listener in a rate-limiter (e.g., requestAnimationFrame or a small timeout-based throttle) inside subscribeToWindowResize so onStoreChange is invoked at most once per animation frame (or at a chosen interval). Implement the throttling wrapper around the event callback in subscribeToWindowResize, ensure the returned cleanup removes the throttled listener and cancels any pending rAF/timeouts, and keep references to the original onStoreChange for removeEventListener so cleanup works correctly; this will reduce how often getSnapshot()/buildBlocks recompute during window resize.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/shared/providers/locale-provider.tsx`:
- Around line 41-42: The fallback localeState should track the most recent
pathname-derived locale so unprefixed routes use that value; compute pathLocale
= getLocaleFromPathname(pathname) and use locale = pathLocale ?? localeState,
and add an effect that whenever pathLocale is non-null it calls
setLocaleState(pathLocale) so the fallback stays synchronized; ensure this keeps
setLocale functioning for unprefixed routes while allowing pathname-derived
locale to override when present (referencing getLocaleFromPathname, localeState,
setLocaleState, pathname, and the existing useEffect).
---
Outside diff comments:
In `@src/shared/hooks/use-throttle.ts`:
- Around line 17-39: The scheduled RAF can call a stale callback when `callback`
changes; introduce a mutable ref (e.g., `callbackRef`) and update
`callbackRef.current = callback` in a small effect that runs on `[callback]`,
then invoke `callbackRef.current(...args)` everywhere (both in the immediate
path and inside the `requestAnimationFrame` handler) instead of using the
`callback` closed over by `useCallback`; keep `rafRef`, `lastCallRef`, and the
existing unmount cleanup that cancels with
`cancelAnimationFrame(rafRef.current)` but remove `callback` from the
`useCallback` deps so the throttled function doesn’t recreate on each callback
change.
---
Nitpick comments:
In `@src/features/user/components/badge-generator.tsx`:
- Around line 19-46: The BadgeCopyButtonProps currently types the prop `type` as
CopyType (which can be null) but every caller passes a concrete copy identifier;
update the prop to a non-nullable variant (e.g., use NonNullable<CopyType> or
Exclude<CopyType, null>) so `BadgeCopyButton`'s `type` cannot be null and
improves type safety; adjust the BadgeCopyButtonProps declaration (and any
related usages if necessary) to use the narrowed type while keeping `copied:
CopyType` as-is.
In `@src/shared/components/ui/heatmap-background.tsx`:
- Around line 14-21: The resize subscription currently calls onStoreChange for
every resize event; throttle it to reduce re-renders by wrapping the listener in
a rate-limiter (e.g., requestAnimationFrame or a small timeout-based throttle)
inside subscribeToWindowResize so onStoreChange is invoked at most once per
animation frame (or at a chosen interval). Implement the throttling wrapper
around the event callback in subscribeToWindowResize, ensure the returned
cleanup removes the throttled listener and cancels any pending rAF/timeouts, and
keep references to the original onStoreChange for removeEventListener so cleanup
works correctly; this will reduce how often getSnapshot()/buildBlocks recompute
during window resize.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8b8c150c-14b7-4b00-bb9c-942d882343ea
📒 Files selected for processing (18)
src/app/global-error.tsxsrc/app/users/[username]/user-profile-client.tsxsrc/features/auth/store/auth-store.tssrc/features/home/components/hero-section.tsxsrc/features/ranking/api/ranking-service.tssrc/features/user/components/badge-generator.tsxsrc/features/user/components/score-info-modal.tsxsrc/features/user/components/stats-chart-impl.tsxsrc/shared/components/command.tsxsrc/shared/components/input.tsxsrc/shared/components/theme-toggle.tsxsrc/shared/components/ui/heatmap-background.tsxsrc/shared/hooks/use-has-mounted.tssrc/shared/hooks/use-media-query.tssrc/shared/hooks/use-reduced-motion.tssrc/shared/hooks/use-throttle.tssrc/shared/providers/locale-provider.tsxtailwind.config.ts
💤 Files with no reviewable changes (1)
- src/shared/components/command.tsx
|
리뷰 코멘트 반영했습니다.
재검증:
반영 커밋: |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/shared/components/ui/heatmap-background.tsx`:
- Around line 61-65: The seed inputs for each block (activeSeed, opacitySeed,
durationSeed, delaySeed, colorSeed) should not include the viewport-dependent
variable width because that causes reseeding on initial render/resizes; update
the seededValue calls in heatmap-background.tsx to use only index-based values
(e.g., index with distinct fixed offsets or multipliers per seed) so each seed
remains stable across width changes while keeping column-count logic separate.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c2344be7-f87c-4e93-9a04-3bc58f1100fc
📒 Files selected for processing (4)
src/features/user/components/badge-generator.tsxsrc/shared/components/ui/heatmap-background.tsxsrc/shared/hooks/use-throttle.tssrc/shared/providers/locale-provider.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- src/shared/providers/locale-provider.tsx
- src/features/user/components/badge-generator.tsx
- src/shared/hooks/use-throttle.ts
1) 요약
react-hooks/set-state-in-effect,react-hooks/static-components,react-hooks/purity,react-hooks/use-memo를 포함한 기존 lint warning 26개를 정리했습니다.2) 연관 이슈
3) 사용자 관점 결과
4) 영향 범위
src/app/users/[username]/user-profile-client.tsxsrc/app/global-error.tsxsrc/features/home/components/hero-section.tsxsrc/features/user/components/badge-generator.tsxsrc/features/user/components/stats-chart-impl.tsxsrc/shared/components/theme-toggle.tsxsrc/shared/components/ui/heatmap-background.tsxuseAuthHydrated, media query/reduced motion, locale sync, throttle hook 구현 정리5) 스크린샷 또는 영상
6) 검증 증거
npm run lintnpm run buildmiddleware.tsdeprecated convention으로 중단npx tsc --noEmit미구축(GRC-04 예정)7) API / 백엔드 연동 확인
8) 리스크 및 롤백
9) 체크리스트
Summary by CodeRabbit
Improvements
Chores