Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughApp에 Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User as 사용자
participant App as App (useToast)
participant Loader as Kakao Script Loader
participant TP as ToastProvider / Context
participant UI as Toast UI
User->>App: 앱 진입 / 지도 초기화
App->>Loader: Kakao Maps 스크립트 로드 시도
Loader-->>App: onerror(로드 실패)
App->>TP: toast({ title, description, variant: "destructive" })
TP->>UI: 토스트 렌더링 (즉시 표시)
TP-->>TP: 4초 타이머로 자동 제거
UI-->>TP: 토스트 제거 요청
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
src/components/ui/use-toast.tsx (3)
27-39: 언마운트 시 남은 타임아웃 정리 필요 (React 경고/메모리 누수 방지)Provider가 언마운트되면 예약된
setTimeout이 실행되며setMessages가 호출될 수 있습니다. 정리 루틴을 추가해 주세요.적용 diff:
-import { +import { createContext, useCallback, useContext, + useEffect, useRef, useState, } from "react"; @@ export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ children, }) => { const [messages, setMessages] = useState<ToastMessage[]>([]); const idRef = useRef(0); + const timeoutsRef = useRef(new Set<ReturnType<typeof setTimeout>>()); @@ const toast = useCallback((opts: ToastOptions) => { const id = idRef.current++; const timeoutId = setTimeout(() => { setMessages((prev) => prev.filter((m) => m.id !== id)); + timeoutsRef.current.delete(timeoutId); }, 4000); + timeoutsRef.current.add(timeoutId); setMessages((prev) => [{ ...opts, id, timeoutId }, ...prev]); }, []); + + useEffect(() => { + return () => { + // clear pending timeouts on unmount + timeoutsRef.current.forEach(clearTimeout); + timeoutsRef.current.clear(); + }; + }, []);
41-52: 지도 상단 인터랙션 차단 최소화: pointer-events/ARIA 보완 제안토스트 컨테이너가 지도 상단 클릭을 가로챌 수 있습니다. 컨테이너엔
pointerEvents: "none"을 주고, 카드에만"auto"를 적용하면 지도 조작 방해를 줄일 수 있습니다. 또한 스크린리더 공지용 ARIA를 추가하세요.적용 diff:
- <div - style={{ + <div + role="status" + aria-live="polite" + aria-atomic="true" + style={{ position: "fixed", left: "50%", transform: "translateX(-50%)", top: 24, zIndex: 9999, + pointerEvents: "none", }} > {messages.map((t) => ( <div key={t.id} style={{ marginTop: 8, background: t.variant === "destructive" ? "#ef4444" : "rgba(0,0,0,0.8)", color: "white", padding: "10px 14px", borderRadius: 8, boxShadow: "0 4px 12px rgba(0,0,0,0.2)", minWidth: 200, textAlign: "center", + pointerEvents: "auto", }} >Also applies to: 56-69
83-91: Fast Refresh 경고 완화: 훅/Provider 분리 고려정적 분석 경고대로 컴포넌트 외 export가 섞여 Fast Refresh 최적화가 떨어질 수 있습니다. 영향은 경미하지만,
ToastProvider.tsx와useToast.ts로 분리하면 경고가 사라집니다. 유지 시 기능상 문제는 없습니다.src/App.tsx (1)
300-307: 에러 토스트 처리 방식 일관화 제안위 분기(라인 270대)와 달리 여기서는 try/catch 없이 호출합니다. 현재 구조상 Provider 보장이 있어 문제는 없으나, 두 경로를 동일한 헬퍼로 묶으면 유지보수가 수월합니다.
예:
const showMapLoadError = () => toast({...})로 추출 후 두 곳에서 사용.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/App.tsx(4 hunks)src/components/ui/use-toast.tsx(1 hunks)src/data/bus.ts(1 hunks)src/main.tsx(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/App.tsx (1)
src/components/ui/use-toast.tsx (1)
useToast(83-89)
src/main.tsx (1)
src/components/ui/use-toast.tsx (1)
ToastProvider(27-81)
🪛 GitHub Check: Build and Test
src/components/ui/use-toast.tsx
[warning] 91-91:
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
[warning] 83-83:
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
🔇 Additional comments (5)
src/data/bus.ts (1)
5-5: 타입 표기 공백 정렬만 변경 — 문제 없습니다런타임/타입 의미 변화 없고 일관성 좋아졌습니다.
src/main.tsx (1)
5-5: 루트에 ToastProvider 래핑 — 적절합니다App 전역에서 토스트 사용 가능해졌고, 의존 관계도 명확합니다. 개발 모드(StrictMode)에서 동일 오류가 두 번 발생하면 토스트가 중복될 수 있으니 실제 실패 시 중복 노출 여부만 확인해 주세요.
Also applies to: 14-16
src/App.tsx (3)
4-4: 토스트 훅 도입 연결 OK
useToast도입 및 구조 분해 할당 문제 없습니다. 의존성 배열에toast포함도 적절합니다.Also applies to: 10-10
270-283: 기존 스크립트 오류 핸들링에 토스트 추가 — 👍 (폴백 콘솔 포함)Provider 외부 사용 가능성을 대비한 try/catch 폴백도 실용적입니다.
374-374: 의존성 배열 업데이트 적절
toast참조 안정성 보장 및 훅 교체 시 재실행을 커버합니다.개발 모드(StrictMode)에서 이 이펙트가 두 번 실행되어 오류 상황에서 토스트가 2회 뜨는지 확인 부탁드립니다. 중복 시 Provider 레벨에서 동일 payload의 연속 토스트 디듀프를 고려할 수 있습니다.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/components/ui/use-toast.tsx (1)
16-19: 브라우저 타이핑 수정 완료 — 이전 리뷰 이슈 해소됨
timeoutId를ReturnType<typeof setTimeout>으로 교체한 점 좋습니다. DOM 타겟에서의NodeJS.Timeout빌드 오류 우려가 사라졌습니다.
🧹 Nitpick comments (7)
src/components/ui/use-toast.tsx (7)
30-39: 언마운트 시 남은 타이머 정리 필요 (경미한 메모리/경고 예방)Provider가 언마운트될 때, 스케줄된
setTimeout을 정리하지 않으면 개발 모드에서 “unmounted component” 경고 가능성이 있습니다. 활성 타이머를 ref로 추적하고 언마운트 시 일괄clearTimeout하세요.적용 diff:
@@ -import { - createContext, - useCallback, - useContext, - useRef, - useState, -} from "react"; +import { + createContext, + useCallback, + useContext, + useEffect, + useRef, + useState, +} from "react"; @@ const [messages, setMessages] = useState<ToastMessage[]>([]); const idRef = useRef(0); + const timersRef = useRef(new Set<ReturnType<typeof setTimeout>>()); const toast = useCallback((opts: ToastOptions) => { const id = idRef.current++; - const timeoutId = setTimeout(() => { - setMessages((prev) => prev.filter((m) => m.id !== id)); - }, 4000); + const timeoutId = setTimeout(() => { + setMessages((prev) => prev.filter((m) => m.id !== id)); + timersRef.current.delete(timeoutId); + }, 4000); + timersRef.current.add(timeoutId); setMessages((prev) => [{ ...opts, id, timeoutId }, ...prev]); }, []); + + useEffect(() => { + return () => { + timersRef.current.forEach(clearTimeout); + timersRef.current.clear(); + }; + }, []);Also applies to: 2-8
41-43: Context value 메모이제이션으로 불필요한 리렌더 방지
value={{ toast }}는 매 렌더마다 새 객체를 만들어 모든 소비자 리렌더를 유발합니다.useMemo로 안정화하세요.적용 diff:
@@ -import { +import { createContext, useCallback, useContext, + useMemo, useRef, useState, } from "react"; @@ - const toast = useCallback((opts: ToastOptions) => { + const toast = useCallback((opts: ToastOptions) => { const id = idRef.current++; @@ - }, []); + }, []); + const ctxValue = useMemo(() => ({ toast }), [toast]); @@ - <ToastContext.Provider value={{ toast }}> + <ToastContext.Provider value={ctxValue}>Also applies to: 2-8, 39-40
54-56: a11y: 스크린 리더 공지(role/aria-live) 추가파괴적 토스트는 즉시 공지(assertive), 일반 토스트는 정중 공지(polite)가 적합합니다.
적용 diff:
- {messages.map((t) => ( - <div - key={t.id} + {messages.map((t) => ( + <div + key={t.id} + role={t.variant === "destructive" ? "alert" : "status"} + aria-live={t.variant === "destructive" ? "assertive" : "polite"}
45-52: 오버레이 클릭 가로채기 방지고정 상단 오버레이가 클릭을 가로챌 수 있습니다. 컨테이너에
pointerEvents: "none"을 주고, 토스트 카드에만"auto"를 설정하세요.적용 diff:
<div style={{ position: "fixed", left: "50%", transform: "translateX(-50%)", top: 24, zIndex: 9999, + pointerEvents: "none", }} > {messages.map((t) => ( <div key={t.id} style={{ + pointerEvents: "auto", marginTop: 8, background: t.variant === "destructive" ? "#ef4444" : "rgba(0,0,0,0.8)",Also applies to: 56-68
58-63: 색 대비(contrast) 개선 제안
#ef4444위의 흰색 텍스트는 소문자 본문 기준 WCAG AA 대비(4.5:1) 미달 가능성이 큽니다. 더 진한 배경([#dc2626]또는[#b91c1c])을 쓰거나 텍스트색을 어둡게 조정 검토 바랍니다.
10-14: 토스트 표시 시간(duration) 옵션화고정 4초 대신 옵션으로 제어 가능하면 재사용성이 올라갑니다(에러 토스트는 더 길게 등).
적용 diff:
type ToastOptions = { title?: string; description?: string; variant?: "default" | "destructive"; + duration?: number; // ms }; @@ - const timeoutId = setTimeout(() => { + const timeoutId = setTimeout(() => { setMessages((prev) => prev.filter((m) => m.id !== id)); - }, 4000); + }, opts.duration ?? 4000);Also applies to: 35-37
83-91: Fast Refresh 경고 해결: 파일 분리 제안정적 분석 경고대로 컴포넌트 외 export가 섞여 있어 Fast Refresh가 비활성화될 수 있습니다.
ToastProvider.tsx(컴포넌트만 export)와use-toast.ts(hook만 export)로 분리하면 경고가 사라집니다. 지금 구조 유지가 필요하면 무시 가능하나, 개발 경험 향상을 위해 분리 권장합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/ui/use-toast.tsx(1 hunks)
🧰 Additional context used
🪛 GitHub Check: Build and Test
src/components/ui/use-toast.tsx
[warning] 91-91:
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
[warning] 83-83:
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
🔇 Additional comments (1)
src/components/ui/use-toast.tsx (1)
27-81: 전반적 구현 품질 양호간결한 API(
toast(opts)), 선입 스택, 변형(variant) 처리 모두 명확합니다. 카카오 맵 로드 실패 시 사용자 피드백 UX가 개선됩니다.
Summary by CodeRabbit
새 기능
리팩터링
스타일