Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded@KwonDeaGeun has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 13 minutes and 20 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (9)
Walkthrough환경 기본값으로 VITE_API_BASE_URL가 설정되고, 버스 위치 폴링 간격이 5000ms에서 7000ms로 늘어났으며, 버스 오버레이에 캐시·회전 정규화·setMap 정리 API(clearAllBusOverlays 포함)와 정류소/버스 오버레이 라이프사이클 분리가 도입되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Hook as useMapOverlays
participant Utils as mapOverlays
participant Cache as BusOverlayCache
participant Map as KakaoMap
Note over Hook,Map: 초기 마운트
Hook->>Utils: createBusStopOverlays(map, busStops)
Utils->>Map: setMap(overlay) for stops
Hook->>Utils: createBusOverlays(map, buses)
Utils->>Cache: check cache per bus
Cache-->>Utils: miss → create overlay, store in cache
Utils->>Map: setPosition + add to map
Note over Hook,Map: 버스 위치 업데이트
Hook->>Utils: createBusOverlays(map, buses)
Utils->>Cache: hit → reuse cached overlay
Utils->>Utils: normalizeRotation(newAngle, prevAngle)
Utils->>Map: setPosition + apply CSS transform (rotate)
Note over Hook,Map: 언마운트 / 전체 정리
Hook->>Utils: clearAllBusOverlays()
Utils->>Map: setMap(null) for cached overlays
Utils->>Cache: clear cache
Estimated code review effort🎯 3 (중간) | ⏱️ ~20분
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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: 0
🧹 Nitpick comments (5)
src/types/kakao.d.ts (1)
18-21:KakaoOverlay.setPosition타입 추가 방향 좋습니다
CustomOverlay.setPosition를 정식으로 타입에 반영해서,createBusOverlays쪽에서 쓰는 패턴과 잘 맞습니다.
후속으로src/utils/mapOverlays.ts의(cached.overlay as { setPosition: (pos: unknown) => void }).setPosition?.(busPosition);부분을 별도 임시 타입 대신
KakaoOverlay를 활용하도록 정리하면 캐스팅을 조금 더 줄일 수 있을 것 같습니다(지금 코드도 동작상 문제는 없어 보입니다).src/api/bus.ts (1)
7-27: 버스 위치 폴링 주기 조정은 문제 없어 보입니다5초 → 7초로 늘려서 서버 부하를 조금 줄이면서도 실시간성은 크게 해치지 않을 것 같습니다.
다만 이 값이 도메인 상 “버스 위치 갱신 주기”와 강하게 연결된 의미라면, 예를 들어const BUS_LOCATION_POLL_INTERVAL_MS = 7000;같은 상수로 분리해 두면 나중에 튜닝·공유 시 의도가 더 드러날 것 같습니다.
.env.sample (1)
1-3:.env.sample기본 URL 추가는 괜찮고, 정렬은 컨벤션에 맞추면 될 것 같습니다샘플에
VITE_API_BASE_URL=https://whatthebus.duckdns.org를 넣어두면 로컬 설정 시 편의성이 높아져서 좋습니다.
dotenv-linter경고처럼 키 알파벳 순서를 맞추고 싶다면 아래처럼 순서를 바꾸는 정도만 해두면 됩니다(필수는 아니고 팀 컨벤션에 맞추면 될 것 같습니다).VITE_API_BASE_URL=https://whatthebus.duckdns.org VITE_KAKAO_MAP_API_KEY= VITE_API_KEY=src/hooks/useMapOverlays.ts (1)
17-50: 정류장/버스 오버레이 분리는 명확하고, map 변경 시 동작만 한 번 더 점검해 보면 좋겠습니다
- 정류장 오버레이를
stopOverlays로 관리하고 의존성 변경 시마다setMap(null) + cleanup을 호출하는 구조는 깔끔하고 메모리/리스너 누수도 잘 방지하고 있습니다.- 버스 오버레이는
createBusOverlays(map, buses)가 내부 캐시와previousBusPositions로 관리하고, 언마운트 시clearAllBusOverlays()만 호출하는 설계도 PR 의도(이전 위치 기반 회전 유지, DOM 재생성 최소화)에 잘 맞습니다.다만 한 가지 케이스만 고려해 볼 수 있습니다:
- 만약 Kakao
map인스턴스 자체가 재생성되어useMapOverlays에 다른map객체가 들어오는 상황이 생기면,
현재createBusOverlays는 캐시된 overlay에 대해setMap(map)을 다시 호출하지 않고setPosition만 호출하고 있어서, 캐시에 남아 있는 기존 overlay가 이전 map에 붙어 있을 가능성이 있습니다.- 이 앱에서 map 인스턴스가 초기화 이후 사실상 바뀌지 않는 구조라면 지금도 실사용에서 문제는 없을 듯하지만, 방어적으로는
map이 변경될 때 한 번clearAllBusOverlays()를 호출하거나,- 혹은
createBusOverlays의 cached 분기에서setMap(map)도 다시 호출해 주는 방식을 고려해 볼 수 있습니다.전체적으로 타입은
unknown을 유지하면서any를 피하고 있어서, 이전 PR에서 말씀하신 타입 안정성 선호도와도 잘 맞는 방향 같습니다. (Based on learnings)src/utils/mapOverlays.ts (1)
13-27: 버스 오버레이 캐시/정리 로직이 잘 구성되어 있고, map 간 공유 가능성만 염두에 두면 좋겠습니다
busOverlayCache를 도입해서{ overlay, img, div }를 묶어 관리하고,
createBusOverlays상단에서 활성 버스 ID 집합과 비교해 비활성 버스를setMap(null)+delete로 제거하는 흐름은 메모리 누수 방지 측면에서 좋습니다.clearAllBusOverlays도setMap(null)호출 후busOverlayCache와previousBusPositions를 함께 정리해서, 페이지 이동/언마운트 시 상태가 깨끗하게 초기화됩니다.for (const busId of busOverlayCache.keys()) { ... busOverlayCache.delete(busId); }패턴은 JSMap에서 합법적인 사용이라 순회 중 삭제로 인한 누락 위험도 거의 없습니다.createBusOverlays반환값의cleanup이 현재는busOverlayCache.delete+previousBusPositions.delete까지만 담당하고 있고setMap(null)은 호출하지 않지만, 실제 사용처에서는cleanup자체가 호출되지 않고clearAllBusOverlays를 통해 일괄 정리되고 있어서 실동작에는 문제가 없습니다.
다만 API 일관성을 위해 나중에cleanup에서도setMap(null)까지 포함시키는 것을 고려해 볼 수 있습니다.전체적으로 캐시 설계와 정리 타이밍은 PR 의도(불필요한 DOM 재생성 제거 + 버스별 오버레이 재사용)에 잘 맞는 구현입니다.
Also applies to: 271-282, 318-361, 369-373
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
.env.sample(1 hunks)src/api/bus.ts(1 hunks)src/hooks/useMapOverlays.ts(3 hunks)src/types/kakao.d.ts(1 hunks)src/utils/mapOverlays.ts(5 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: KwonDeaGeun
Repo: KwonDeaGeun/WhatTheBus-Web PR: 21
File: src/App.tsx:16-23
Timestamp: 2025-09-22T04:45:54.455Z
Learning: KwonDeaGeun은 TypeScript에서 any 타입 사용을 피하고 더 타입 안전한 코드를 선호한다.
🧬 Code graph analysis (1)
src/hooks/useMapOverlays.ts (1)
src/utils/mapOverlays.ts (3)
createBusStopOverlays(190-260)createBusOverlays(262-376)clearAllBusOverlays(21-27)
🪛 dotenv-linter (4.0.0)
.env.sample
[warning] 2-2: [UnorderedKey] The VITE_API_BASE_URL key should go before the VITE_KAKAO_MAP_API_KEY key
(UnorderedKey)
🔇 Additional comments (1)
src/utils/mapOverlays.ts (1)
49-67: 회전 각도 정규화와 이전 값 재사용 로직이 PR 목적에 잘 부합합니다
normalizeRotation에서
- 이전/새 각도를 각각 0~360도로 정규화하고,
- 차이를
[-180, 180]범위 내 최단 경로로 조정한 뒤,- 다시 0~360도로 돌려놓는 수식은 기대하는 “최단 거리 회전” 동작을 정확히 구현하고 있습니다.
createBusOverlays에서
- 위치가 실제로 바뀐 경우에만
calculateAngle을 사용해 새 각도를 계산하고,- 위치가 그대로면 이전
rotation값을 그대로 재사용하는 것도 불필요한 회전/transition을 막는 좋은 처리입니다.- 첫 입력에서는
previousData가 없어서 0도로 시작하고, 이후부터는previousBusPositions에 저장된 회전값을 기준으로 부드럽게 이어지는 구조라 PR 제목(“이전 값을 저장하여 회전하도록 수정”)과도 잘 맞습니다.- CSS 측면에서도
transformOrigin = "center center"+transition: transform 0.3s ease-out으로 시각적으로 자연스러운 회전을 줄 수 있어 보여서, 구현 전반이 안정적입니다.이 부분은 현재 상태 그대로도 충분히 만족스러운 것 같습니다.
Also applies to: 287-316, 297-305, 327-348
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/utils/mapOverlays.ts (1)
13-27: 캐싱 메커니즘이 잘 구현되었습니다.버스 오버레이를 재사용하여 DOM 재생성을 방지하는 좋은 접근 방식입니다. 다만,
clearAllBusOverlays함수에서 Map을 순회하면서 동시에 삭제하는 것보다 더 명확한 패턴을 고려해보세요.다음과 같이 리팩토링하면 의도가 더 명확해집니다:
export const clearAllBusOverlays = () => { - for (const [busId, cached] of busOverlayCache.entries()) { + const entries = Array.from(busOverlayCache.entries()); + for (const [busId, cached] of entries) { (cached.overlay as { setMap: (m: unknown) => void }).setMap(null); - busOverlayCache.delete(busId); - previousBusPositions.delete(busId); } + busOverlayCache.clear(); + previousBusPositions.clear(); };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/utils/mapOverlays.ts(5 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: KwonDeaGeun
Repo: KwonDeaGeun/WhatTheBus-Web PR: 21
File: src/App.tsx:16-23
Timestamp: 2025-09-22T04:45:54.455Z
Learning: KwonDeaGeun은 TypeScript에서 any 타입 사용을 피하고 더 타입 안전한 코드를 선호한다.
🔇 Additional comments (4)
src/utils/mapOverlays.ts (4)
49-67: 최단 경로 회전 로직이 정확하게 구현되었습니다.
normalizeRotation함수는 각도 차이가 180도를 넘을 때 반대 방향으로 회전하도록 하여 시각적으로 자연스러운 회전을 제공합니다. 알고리즘이 수학적으로 정확합니다.
271-281: 비활성 버스 정리 로직이 올바르게 구현되었습니다.더 이상 활성 상태가 아닌 버스를 캐시와 이전 위치 맵에서 제거하여 메모리 누수를 효과적으로 방지합니다.
297-304: 회전 정규화가 올바르게 적용되었습니다.이전 회전 값을 고려하여 최단 경로로 회전하도록 하여 부드러운 애니메이션 효과를 제공합니다.
366-381: setMap 및 cleanup 로직이 안전하게 구현되었습니다.
cached변수는 이 시점에서 항상 정의되어 있지만, 방어적으로 존재 여부를 확인하는 것은 안전한 코딩 관행입니다. cleanup에서 오버레이를 지도에서 제거하고 캐시와 이전 위치 데이터를 모두 정리하는 것이 적절합니다.
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/utils/mapOverlays.ts (1)
256-268: 불필요한 타입 캐스팅을 제거하세요.
KakaoOverlay타입이 이미setMap메서드를 포함하도록 정의되어 있으므로, Line 262와 266-267의 타입 캐스팅은 불필요합니다.Based on learnings
다음과 같이 수정하세요:
const markerPosition = new window.kakao.maps.LatLng(stop.lat, stop.lng); - const overlay = new window.kakao.maps.CustomOverlay({ + const overlay: KakaoOverlay = new window.kakao.maps.CustomOverlay({ position: markerPosition, content: busIconDiv, yAnchor: 1, }); - (overlay as unknown as { setMap: (m: unknown) => void }).setMap(map); + overlay.setMap(map); // Return overlay with cleanup method return { - setMap: (m: unknown) => { - (overlay as unknown as { setMap: (m: unknown) => void }).setMap(m); + setMap: (m) => { + overlay.setMap(m); }, cleanup: () => {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/hooks/useKakaoMap.ts(2 hunks)src/hooks/useMapOverlays.ts(2 hunks)src/types/kakao.d.ts(2 hunks)src/utils/mapOverlays.ts(7 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: KwonDeaGeun
Repo: KwonDeaGeun/WhatTheBus-Web PR: 21
File: src/App.tsx:16-23
Timestamp: 2025-09-22T04:45:54.455Z
Learning: KwonDeaGeun은 TypeScript에서 any 타입 사용을 피하고 더 타입 안전한 코드를 선호한다.
📚 Learning: 2025-09-22T04:45:54.455Z
Learnt from: KwonDeaGeun
Repo: KwonDeaGeun/WhatTheBus-Web PR: 21
File: src/App.tsx:16-23
Timestamp: 2025-09-22T04:45:54.455Z
Learning: KwonDeaGeun은 TypeScript에서 any 타입 사용을 피하고 더 타입 안전한 코드를 선호한다.
Applied to files:
src/utils/mapOverlays.ts
🧬 Code graph analysis (3)
src/utils/mapOverlays.ts (2)
src/types/kakao.d.ts (2)
KakaoMap(8-16)KakaoOverlay(18-28)src/data/bus.ts (1)
Bus(1-6)
src/hooks/useMapOverlays.ts (2)
src/types/kakao.d.ts (1)
KakaoMap(8-16)src/utils/mapOverlays.ts (3)
createBusStopOverlays(205-275)clearAllBusOverlays(36-42)createBusOverlays(277-398)
src/hooks/useKakaoMap.ts (1)
src/types/kakao.d.ts (1)
KakaoMap(8-16)
🔇 Additional comments (9)
src/types/kakao.d.ts (1)
1-28: 타입 정의가 명확하고 안전하게 개선되었습니다.
KakaoLatLng,KakaoMap,KakaoOverlay인터페이스를 export하여 다른 파일에서 타입 안전하게 사용할 수 있게 했습니다. 이는 이전에 학습한 내용처럼unknown과any타입 사용을 줄이는 좋은 접근입니다.Based on learnings
src/hooks/useKakaoMap.ts (1)
2-2: 타입 안전성이 크게 개선되었습니다.
unknown에서KakaoMap | null로 변경하여 타입 안전한 코드를 작성할 수 있게 되었습니다.Based on learnings
Also applies to: 14-14
src/hooks/useMapOverlays.ts (1)
18-54: 오버레이 관리 로직이 잘 분리되었습니다.버스 정류장 오버레이와 버스 오버레이를 별도의 effect로 관리하여 각각의 생명주기를 독립적으로 처리하는 것은 좋은 설계입니다. 버스 오버레이 업데이트 시 캐싱을 활용하여 성능도 최적화했습니다.
src/utils/mapOverlays.ts (6)
6-18: 매직 넘버를 상수로 추출한 것은 좋은 개선입니다.하드코딩된 값들을 명명된 상수로 추출하여 가독성과 유지보수성이 향상되었습니다.
29-42: 타입 안전성과 메모리 관리가 개선되었습니다.캐시 타입을
unknown에서KakaoOverlay로 변경했고,clearAllBusOverlays함수로 모든 오버레이를 정리하여 메모리 누수를 방지합니다.Based on learnings
64-82: 회전 정규화 로직이 정확합니다.최단 경로로 회전하도록 각도를 정규화하는 로직이 올바르게 구현되었습니다. 360도 경계를 넘을 때 부드러운 회전 애니메이션을 보장합니다.
283-296: 비활성 버스 정리 로직이 메모리 누수를 효과적으로 방지합니다.현재 활성 버스 집합과 캐시를 비교하여 비활성 버스의 오버레이를 제거하고 캐시에서 삭제하는 로직이 올바르게 구현되었습니다.
333-379: 캐시 재사용 로직이 효율적으로 구현되었습니다.DOM 요소를 재사용하고 CSS transform으로 회전을 업데이트하는 것은 성능에 좋은 접근입니다. 이전 리뷰에서 지적된 불필요한 타입 캐스팅도 제거되어
cached.overlay.setPosition()및cached.overlay.setMap()을 직접 호출합니다.
306-324: 회전 계산 로직이 정확하고 효율적입니다.위치가 변경된 경우에만 각도를 계산하고, 변경되지 않은 경우 이전 회전 값을 재사용하여 불필요한 계산을 방지합니다.
normalizeRotation을 사용하여 부드러운 회전을 보장합니다.
Summary by CodeRabbit
릴리스 노트
성능 개선
변경사항