[fix] 상세페이지에서 clubName이 undefined되는 문제를 해결한다#886
Conversation
- useTrackPageView 훅에 skip 파라미터추가하여 트래킹 제어 기능 구현 - ClubDetailPage에서 데이터 로딩 완료 시점까지 트래킹 지연 처리 - useEffect 의존성 배열에 clubName 추가하여 데이터 업데이트 반영
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| 응집도 / 파일(s) | 변경 요약 |
|---|---|
페이지 뷰 추적 훅 개선 frontend/src/hooks/useTrackPageView.ts |
훅 시그니처에 선택적 skip: boolean = false 추가. clubNameRef, isTracked, startTime 초기화 및 동기화 도입. Visited/Duration 이벤트에서 clubNameRef.current 사용. Duration 전송에 단일 전송(race-condition) 가드 추가. unload/visibility 리스너 유지 및 정리. effect 의존성에 location.pathname, clubName, skip 포함. |
클럽 상세 페이지 호출 업데이트 frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx |
useTrackPageView(PAGE_VIEW.CLUB_DETAIL_PAGE, clubDetail?.name) → useTrackPageView(PAGE_VIEW.CLUB_DETAIL_PAGE, clubDetail?.name, !clubDetail)로 변경해 데이터 미준비 시 추적을 건너뜀. |
타입스크립트 구성 포맷팅 frontend/tsconfig.json |
paths, types, include, exclude 등 배열을 멀티라인으로 재포맷(의미적 변경 없음). |
Sequence Diagram(s)
sequenceDiagram
participant Page as ClubDetailPage
participant Hook as useTrackPageView
participant Tracker as TrackingSystem
Page->>Hook: useTrackPageView(page, clubName, skip)
alt skip == true
Note right of Hook `#f9f0c1`: effect 조기 종료 — 추적 수행 안함
Hook-->>Hook: 초기화만 수행 (isTracked 리셋, startTime 재설정)
else skip == false
Note right of Hook `#e6f7e6`: Visited 이벤트 전송 (clubNameRef.current 사용)
Hook->>Tracker: send Visited (clubNameRef.current)
Note right of Hook `#e6f7e6`: startTime 기록 및 Duration 추적 대기
par 사용자 이탈(unload/visibility) or 타임아웃
alt Duration not sent yet
Hook->>Tracker: send Duration (guard: isTracked -> 한 번만 전송)
end
end
end
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
- 훅 내부의 타이밍/리프 상태(isTracked, startTime, clubNameRef)와 이벤트 리스너 정리 검증 필요
- ClubDetailPage 호출 변경이 실제로 undefined 전송을 방지하는지 확인
- 의존성 배열 변경으로 인한 재실행/중복 전송 시나리오 점검
Possibly related issues
#885— 동일 훅에skip플래그를 추가해 undefined인clubName전송을 방지하려는 변경과 직접 연관됨.MOA-386— (전송된 이벤트의 clubName 속성은 undefined가 아니어야 한다) 본 PR의 skip 플래그가 이 목표를 달성하기 위해 도입된 것으로 보임.
Possibly related PRs
- PR
#408— 같은 파일(useTrackPageView.ts)을 수정해 startTime 관련 초기화/정리 변경을 포함, 코드 수준 연관성 높음. - PR
#804— Duration 추적의 race-condition/isTracked 처리 개선을 다룸, 본 PR의 단일 전송 가드와 관련 있음. - PR
#684— useTrackPageView 훅의 의존성·동작 변경을 포함해 동일 파일을 수정한 PR로 연관성 있음.
Suggested labels
🛠Fix, 💻 FE
Suggested reviewers
- oesnuj
- lepitaaar
- PororoAndFriends
Pre-merge checks and finishing touches
❌ Failed checks (1 inconclusive)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Out of Scope Changes check | ❓ Inconclusive | tsconfig.json의 포맷팅 변경만이 범위 외 수정으로 보입니다. 핵심 기능 변경은 모두 clubName 추적 문제 해결과 직접 관련이 있습니다. | tsconfig.json의 포맷팅 변경이 의도적인 것인지 확인하세요. 필요시 별도 PR로 분리하는 것을 고려하세요. |
✅ Passed checks (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | PR 제목이 주요 변경 사항을 명확하게 요약합니다. 상세페이지에서 clubName이 undefined되는 문제 해결이라는 핵심 목표를 직접적으로 나타냅니다. |
| Linked Issues check | ✅ Passed | PR 변경 사항이 MOA-386의 요구사항을 완전히 충족합니다. useTrackPageView에 skip 플래그를 추가하고, clubDetail이 준비될 때까지 추적을 지연시켜 undefined clubName 문제를 해결합니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
✨ Finishing touches
- 📝 Generate docstrings
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Post copyable unit tests in a comment
- Commit unit tests in branch
fix/#885-mixpanel-club-name-tracking-MOA-386
📜 Recent review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
frontend/src/hooks/useTrackPageView.ts(3 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Learnt from: seongwon030
Repo: Moadong/moadong PR: 548
File: frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx:17-57
Timestamp: 2025-07-19T05:05:10.196Z
Learning: ClubDetailPage.tsx에서 notJoinedClubNames 배열의 하드코딩은 의도적인 설계 결정입니다. 개발자가 명시적으로 하드코딩을 선택했으므로 이에 대한 리팩토링 제안을 하지 않아야 합니다.
📚 Learning: 2025-03-19T05:18:07.818Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Applied to files:
frontend/src/hooks/useTrackPageView.ts
📚 Learning: 2025-07-19T05:05:10.196Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 548
File: frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx:17-57
Timestamp: 2025-07-19T05:05:10.196Z
Learning: ClubDetailPage.tsx에서 notJoinedClubNames 배열의 하드코딩은 의도적인 설계 결정입니다. 개발자가 명시적으로 하드코딩을 선택했으므로 이에 대한 리팩토링 제안을 하지 않아야 합니다.
Applied to files:
frontend/src/hooks/useTrackPageView.ts
🔇 Additional comments (1)
frontend/src/hooks/useTrackPageView.ts (1)
5-9: skip 플래그 + clubNameRef 설계가 요구사항을 잘 만족합니다.
skip플래그로 초기 렌더 시(예:clubDetail미존재) effect를 바로 빠져나가고, 이후skip이false가 될 때에만Visited/Duration이벤트를 쏘도록 한 구조는 이번 이슈(초기clubName이undefined로 로깅되던 문제)를 깔끔하게 해결합니다. 또한clubNameRef를 통해Duration이벤트에서도 최신clubName을 안정적으로 사용하도록 한 점도 적절해 보입니다. 다른 호출 지점들(세 번째 인자를 넘기지 않는 기존 호출 포함)에 대해서도 의도한 대로 이벤트가 쏴지는지만 한 번만 통합 테스트/로그로 확인해 주세요.Also applies to: 17-23, 28-29, 41-42, 57-57
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 @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
frontend/src/hooks/useTrackPageView.ts(2 hunks)frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx(1 hunks)frontend/tsconfig.json(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
📚 Learning: 2025-03-19T05:18:07.818Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Applied to files:
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx
📚 Learning: 2025-07-19T05:05:10.196Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 548
File: frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx:17-57
Timestamp: 2025-07-19T05:05:10.196Z
Learning: ClubDetailPage.tsx에서 notJoinedClubNames 배열의 하드코딩은 의도적인 설계 결정입니다. 개발자가 명시적으로 하드코딩을 선택했으므로 이에 대한 리팩토링 제안을 하지 않아야 합니다.
Applied to files:
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx
🧬 Code graph analysis (1)
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx (1)
frontend/src/constants/eventName.ts (1)
PAGE_VIEW(74-88)
🔇 Additional comments (3)
frontend/tsconfig.json (1)
17-32: LGTM!포매팅 변경만 있으며 의미론적 변경은 없습니다.
frontend/src/hooks/useTrackPageView.ts (1)
5-9: LGTM!
skip파라미터 추가가 올바르게 구현되었습니다. 데이터가 준비될 때까지 추적을 지연시키는 PR의 목적에 부합합니다.frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx (1)
35-35: LGTM!
clubDetail의 존재 여부에 따라 추적을 지연시키는 로직이 올바르게 구현되었습니다.clubDetail이 로드되기 전에는skip=true로 추적을 건너뛰고, 데이터가 준비되면skip=false로 추적을 시작합니다.
- clubName을 useRef로 관리하여 useEffect 의존성 문제 해결 및 최신 값 보장 - 트래킹 시작 시점(skip 해제 시)에 상태 초기화 로직 추가하여 정확도 향상
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/hooks/useTrackPageView.ts (1)
47-56: 이벤트 리스너 cleanup 버그로 인한 메모리 누수가 발생합니다.47-51번 라인에서
visibilitychange이벤트에 익명 화살표 함수를 등록했지만, 56번 라인에서는trackPageDuration함수를 직접 전달하여 제거를 시도합니다. 이 두 함수는 서로 다른 참조이므로 리스너가 제거되지 않고 메모리에 남습니다.다음 diff를 적용하여 리스너 참조를 일치시키세요:
+ const handleVisibilityChange = () => { + if (document.hidden) { + trackPageDuration(); + } + }; + window.addEventListener('beforeunload', trackPageDuration); - document.addEventListener('visibilitychange', () => { - if (document.hidden) { - trackPageDuration(); - } - }); + document.addEventListener('visibilitychange', handleVisibilityChange); return () => { trackPageDuration(); window.removeEventListener('beforeunload', trackPageDuration); - document.removeEventListener('visibilitychange', trackPageDuration); + document.removeEventListener('visibilitychange', handleVisibilityChange); };
🧹 Nitpick comments (1)
frontend/src/hooks/useTrackPageView.ts (1)
58-58: 의존성 배열에pageName추가를 고려하세요.
pageName이 25번, 38번 라인에서 사용되지만 의존성 배열에 포함되지 않았습니다. React의 exhaustive-deps 규칙에 따르면 effect 내에서 사용되는 모든 값은 의존성 배열에 포함되어야 합니다.실무에서
pageName은 컴포넌트 인스턴스마다 상수이므로 큰 문제는 없겠지만, 일관성과 린트 규칙 준수를 위해 추가하는 것이 좋습니다.다음 diff를 적용하세요:
-}, [location.pathname, clubName, skip]); +}, [location.pathname, clubName, skip, pageName]);또는 앞서 제안한 대로
clubName을 제거하고pageName을 추가하는 방식도 가능합니다:-}, [location.pathname, clubName, skip]); +}, [location.pathname, skip, pageName]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
frontend/src/hooks/useTrackPageView.ts(3 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Learnt from: seongwon030
Repo: Moadong/moadong PR: 548
File: frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx:17-57
Timestamp: 2025-07-19T05:05:10.196Z
Learning: ClubDetailPage.tsx에서 notJoinedClubNames 배열의 하드코딩은 의도적인 설계 결정입니다. 개발자가 명시적으로 하드코딩을 선택했으므로 이에 대한 리팩토링 제안을 하지 않아야 합니다.
📚 Learning: 2025-07-19T05:05:10.196Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 548
File: frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx:17-57
Timestamp: 2025-07-19T05:05:10.196Z
Learning: ClubDetailPage.tsx에서 notJoinedClubNames 배열의 하드코딩은 의도적인 설계 결정입니다. 개발자가 명시적으로 하드코딩을 선택했으므로 이에 대한 리팩토링 제안을 하지 않아야 합니다.
Applied to files:
frontend/src/hooks/useTrackPageView.ts
📚 Learning: 2025-03-19T05:18:07.818Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Applied to files:
frontend/src/hooks/useTrackPageView.ts
🔇 Additional comments (3)
frontend/src/hooks/useTrackPageView.ts (3)
5-9: skip 파라미터 추가가 적절합니다.
skip파라미터를 통해clubDetail이 로드되기 전 추적을 지연시키는 방식은 PR 목표를 정확히 달성합니다. 기본값false로 하위 호환성도 유지됩니다.
13-17: clubNameRef 동기화는 올바르나, 의존성 배열 문제가 남아있습니다.
clubNameRef를 통해 최신clubName을 추적하는 구조는 좋습니다. 하지만 58번 라인의 의존성 배열에clubName이 여전히 포함되어 있어,clubName이 변경될 때마다 메인 effect가 재실행되고 중복 "Visited" 이벤트가 발생할 수 있습니다.현재 사용 사례(ClubDetailPage)에서는
clubName이 undefined → 값으로 한 번만 변경되고, 동시에skip도 true → false로 변경되므로 실질적 문제는 없을 수 있으나, 향후 동일 페이지에서clubName이 재변경되는 경우 중복 추적이 발생합니다.이전 리뷰에서 권장한 방식(의존성 배열에서
clubName제거)을 완전히 적용하려면 다음 diff를 적용하세요:useEffect(() => { if (skip) return; isTracked.current = false; startTime.current = Date.now(); mixpanel.track(`${pageName} Visited`, { url: window.location.href, timestamp: startTime.current, referrer: document.referrer || 'direct', clubName: clubNameRef.current, }); // ... 나머지 코드 ... -}, [location.pathname, clubName, skip]); +}, [location.pathname, skip, pageName]);이렇게 하면
clubName변경 시 effect가 재실행되지 않으면서도,clubNameRef를 통해 항상 최신 값이 이벤트에 포함됩니다.
19-23: 이전 리뷰 피드백이 올바르게 반영되었습니다.
skip체크 후 refs를 리셋하는 로직(22-23번 라인)이 추가되어, 이전 리뷰에서 지적된 "페이지 전환 시 refs를 리셋해야 합니다" 이슈가 해결되었습니다. 이제 각 페이지 뷰마다 새로운 추적 상태로 시작합니다.
lepitaaar
left a comment
There was a problem hiding this comment.
문제해결하신부분 잘봤습니다. 아래리뷰만 답변달아주세요~!
#️⃣연관된 이슈
📝작업 내용
1. clubDetail을 가져오는 시점
useGetClubDetail로 데이터를 가져오는 동안 clubDetail은
undefined입니다.2. useTrackPageView 로깅 시점
useTrackPageView는 clubDetail.tsx 가 처음 렌더링 될 때 실행됩니다. 이때 전달되는 clubName은 undefined가 됩니다.3. 데이터 로드 시
만약 clubDetail이 로드되었다 해도, useTrackPageView 내부의 useEffect가 clubName 변경을 감지하지 않도록 되어 있어
결국엔 clubName 로깅이 실패하게 됩니다.
skip으로 로깅 지연 시키기
useTrackPageView에 skip 파라미터를 추가한 다음 skip이 null 또는 undefined일 시 로깅하지 않도록 합니다.clubDetail.tsx에서는 이렇게 사용합니다.
not null assertion으로 clubDetail의
null | undefined여부를 skip으로 전달합니다.만약
null | undefined이라면 skip이 true이므로 로깅하지 않습니다.잠시 후 data가 도착하고 skip은 false가 되고난 다음 로깅이 완료됩니다.
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
릴리스 노트
개선사항
문서/구성
✏️ Tip: You can customize this high-level summary in your review settings.