feat/#118-date-click-race-fix 날짜 연속 클릭 시 선택 상태 롤백/미입력 버그 수정#119
feat/#118-date-click-race-fix 날짜 연속 클릭 시 선택 상태 롤백/미입력 버그 수정#119
Conversation
날짜 연속 클릭 시 stale closure로 인한 상태 롤백 버그 수정의 기반. HostRangeSelectorProps.onChange가 Date[] 직접 전달과 (prev: Date[]) => Date[] updater function 모두를 수용하도록 변경. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handleDateChange가 Date[]와 updater function 모두를 수용하도록 확장. selectedDatesRef/formattedDatesRef를 추가하여 투표 제출 시 stale state 전송을 방지. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
onChange(toggleDatesSmart(selectedDates, newRange))를 onChange((prevDates) => toggleDatesSmart(prevDates, newRange))로 변경. React가 최신 상태를 보장하므로 빠른 연속 클릭 시 이전 선택이 롤백되는 문제가 해결됨. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- onChange 콜백의 union 타입을 소비자 전체에 전파 - 투표 제출 시 formattedDatesRef.current 사용으로 stale state 방지 - tracking 함수에서 updater function일 때 이벤트 스킵 처리 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- spec.md: 버그 명세 (연속 클릭 시 상태 롤백/미입력) - plan.md: 구현 계획 (updater 패턴 전환 전략) - tasks.md: 태스크 목록 및 실행 순서 - checklists/requirements.md: 품질 체크리스트 - CLAUDE.md: agent context 업데이트 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
yejinleee
left a comment
There was a problem hiding this comment.
코드 리뷰
전체적으로 stale closure 문제 분석과 updater function 패턴 적용이 정확합니다. PR 설명도 훌륭합니다. 한 가지 이슈가 있어서 코멘트 남깁니다.
[Bug] Amplitude 트래킹 이벤트 누락
ReactDatepickerAdapter의 handleMouseUp에서 이제 항상 updater function을 전달합니다:
onChange((prevDates) => toggleDatesSmart(prevDates, newRange));그런데 handleDateChangeWithTracking에서는 typeof dates !== 'function'일 때만 trackEvent를 호출합니다:
const handleDateChangeWithTracking = (
dates: Date[] | ((prev: Date[]) => Date[]),
) => {
if (typeof dates !== 'function') {
trackEvent('host_date_select', { total_days: dates.length });
}
handleDateChange(dates);
};updater function은 항상 typeof === 'function'이므로, 이 PR이 머지되면 host_date_select, voter_date_vote, voter_date_edit 세 이벤트가 모두 발화되지 않습니다.
DateSelectPage.tsx, ParticipantRegisterDatePage.tsx, ParticipantEditDatePage.tsx 세 파일 모두 동일한 문제입니다.
|
클로드 야뮤지게 정리하네 |
유니온 타입 Date[] | ((prev) => Date[])에서 실제로 Date[]가 전달되는 경로가 없어 typeof 분기가 트래킹을 항상 스킵하던 버그를 수정한다. onChange를 updater function만 받도록 좁혀 불필요한 분기를 제거한다. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Amplitude 트래킹 누락 수정 완료좋은 리뷰 감사합니다! 지적해주신 트래킹 누락 이슈를 수정했습니다. 원인
수정 방향단순히 분기를 추가하는 것이 아니라, 근본적으로
Before: // 유니온 타입 → typeof 분기 필요 → Date[] 분기에서만 tracking → updater일 때 누락
const handleDateChangeWithTracking = (
dates: Date[] | ((prev: Date[]) => Date[]),
) => {
if (typeof dates !== 'function') {
trackEvent('host_date_select', { total_days: dates.length });
}
handleDateChange(dates);
};After: // updater only → 분기 불필요 → 항상 tracking 실행
const handleDateChangeWithTracking = (updater: (prev: Date[]) => Date[]) => {
handleDateChange((prev) => {
const next = updater(prev);
trackEvent('host_date_select', { total_days: next.length });
return next;
});
};변경 파일
|
🚩 연관 이슈
closed #118
📝 작업 내용
🐛 어떤 문제가 있었나요?
캘린더에서 날짜를 빠르게 연속 클릭하면, 일부 날짜가 선택되지 않거나 이전에 선택한 날짜가 해제되는(롤백) 현상이 발생했습니다.
이 버그는 호스트의 모임 생성 날짜 선택과 참여자의 투표 날짜 선택 모두에서, 모바일(터치)과 데스크톱(마우스) 환경 모두에서 재현됩니다.
재현 방법
🔍 원인이 뭐였나요?
ReactDatepickerAdapter의handleMouseUp에서 날짜 토글을 계산할 때 stale closure 문제가 있었습니다.React의
useState는 비동기적으로 업데이트됩니다. 빠른 연속 클릭 시:[]→[A][][A]→[A, B][]← 아직 갱신 안 됨[A, B]→[A, B, C][]← 여전히 이전 값t2에서
selectedDates가 아직[]이므로toggleDatesSmart([], [B])→[B]가 되어 A가 사라집니다.✅ 어떻게 해결했나요?
React의 updater function 패턴 (
setState(prev => ...))을 도입하여, 항상 최신 상태를 기반으로 토글을 계산하도록 변경했습니다.추가로 해결한 문제: 투표 제출 시 stale state
날짜를 선택한 직후 바로 "투표하기" 버튼을 누르면,
formattedDates(useMemo)가 아직 갱신되지 않아 마지막 선택이 누락될 수 있었습니다.useRef로 최신 상태를 동기적으로 추적하여 해결했습니다.📁 변경 파일 요약
host-range-selector/model/types.tsonChange타입을 updater function 지원으로 확장host-range-selector/model/useDateSelection.tsformattedDatesRef추가host-range-selector/ui/ReactDatepickerAdapter.tsxhandleMouseUp에서 updater 패턴 사용meet-create-date/ui/DateSelectPage.tsxparticipant-register-date/**formattedDatesRef사용participant-edit-date/**formattedDatesRef사용🗣️ 리뷰 요구사항 (선택)