2025. 3. 25. 19:30ㆍ프론트엔드/REACT
🎯 구현 목적
‘중요한 옵션 선택’은 이번 버전의 핵심 유료 기능이며, 사용자에게 제공하는 가치의 중심입니다.
사실 기능의 핵심 원리 자체는 단순합니다. 매칭에 있어 가장 중요한 우선순위 한 가지만 AI에게 전달하면 됩니다.
정말 간단하게 만들자면, 버튼 4개 중 하나를 클릭해서 고르는 구조도 가능합니다.
모달도, 슬라이드도, 인터랙션도 없이 말이죠.
하지만 저는 그렇게 하지 않았습니다.
"단순한 기능일수록 더 강한 경험을 줘야 한다."
그 이유는, 이것이 유료 옵션이기 때문입니다.
사용자는 그만큼 더 몰입감 있고 가치 있는 체험을 받아야 한다고 생각했습니다.
초기에는 ‘우선순위 선택’이라는 이름으로 슬라이드형 인터랙션을 고집했고,
이후 ‘중요한 옵션 선택’으로 이름은 바뀌었지만, 슬라이드 효과는 그대로 남겨두었습니다.
🎮 사용자가 느끼는 경험을 위해 의도한 UX 요소들
- 드래그 앤 드롭을 통한 적극적인 선택 과정
- 선택된 항목이 리스트에서 자연스럽게 사라지고, 다른 항목이 부드럽게 올라오는 애니메이션
- 말풍선 등장: 상단 텍스트와 하단 텍스트가 순차적으로 등장하는 Fade In 효과
- 선택 취소 시: 리스트에 빈 공간을 만들고 옵션이 자연스럽게 다시 나타나는 전환
- 전반적으로 부드럽고 매끄러운 인터랙션을 통해, 단순히 “기능을 수행하는 것”이 아니라
→ **기억에 남는 사용 경험(UX)**으로 남도록 설계했습니다.
✨ 주요 기능
1️⃣ 드래그 앤 드롭 (모바일 터치 기반)
옵션을 길게 누르면 touchstart → touchmove → touchend 이벤트가 동작하고,
드롭 존에 올려놓으면 해당 옵션이 우선순위 항목으로 등록됩니다.
const handleTouchStart = (item, e) => {
setTouchingItem(item);
setTouchPos({
x: e.touches[0].clientX,
y: e.touches[0].clientY,
});
setIsDragging(true);
};
2️⃣ 선택 항목 애니메이션 효과
선택된 옵션은 상단에 강조되며 fade-in 애니메이션으로 등장하고,
"선택 취소" 버튼을 누르면 부드럽게 사라지도록 fade-out 처리됩니다.
const handleCancelSelection = () => {
setFadeOut(true);
setTimeout(() => {
setSelectedItem(null);
setFadeOut(false);
}, 500); // 애니메이션 시간
};
CSS 예시:
@keyframes fadeOutTop {
from { opacity: 1; transform: translateY(0); }
to { opacity: 0; transform: translateY(-50px); }
}
.fade-out-top {
animation: fadeOutTop 0.5s forwards;
}
3️⃣ 선택된 옵션에 따른 문장 생성
Recoil에 저장된 선택값을 기반으로, 사용자가 이해하기 쉬운 문장을 자동 생성합니다.
const priorityMessages = {
mbti: (value) => `${value}인 사람이면 좋겠어!`,
hobby: (value) => `${value}에 관심이 많은 사람이면 좋겠어!`,
};
결과 예시:
감정형인 사람이면 좋겠어!
산책에 관심이 많은 사람이면 좋겠어!
4️⃣ 스크롤 가능한 콘텐츠 영역
옵션이 많아졌을 때 모달 내부에만 스크롤이 적용되도록 처리했습니다.
하단 버튼은 항상 고정되도록 만들기 위해, .match-modal-body에 overflow-y: auto를 주고
padding-bottom을 넉넉히 확보했습니다.
.match-modal-body {
flex: 1;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
padding-bottom: 90px;
}
🧪 구현 중 겪었던 문제와 해결법
문제 상황 원인 해결 방법
| Invalid hook call 오류 | useState를 컴포넌트 바깥에 선언 | 함수 컴포넌트 내부로 옮김 |
| 선택 취소 시 갑작스러운 사라짐 | 애니메이션 없이 상태만 초기화 | fadeOut 상태 추가 후 setTimeout으로 자연스럽게 제거 |
| 모바일 터치 스크롤이 부자연스러움 | inertia 스크롤 미적용 | -webkit-overflow-scrolling: touch 적용 |
| 하단 버튼 가려짐 | 내부 콘텐츠가 버튼 아래까지 확장 | padding-bottom으로 해결 |
🎨 사용자 경험을 위한 디테일
- 말풍선 애니메이션("AI가 이걸 제일 중요하게 생각할게요!")로 피드백 제공
- 버튼의 enabled / disabled 상태 구분을 시각적으로 명확하게 표현
- 선택 취소 시에도 자연스럽게 사라지는 부드러운 전환 처리
'프론트엔드 > REACT' 카테고리의 다른 글
| [CATSPOT]React + Recoil 기반 계단 애니메이션 구현 (0) | 2025.03.27 |
|---|---|
| React 드래그 요소가 선택 취소 후 원래 자리로 돌아가지 않는 문제 해결하기 (0) | 2025.03.26 |
| 📌 [React] 버튼 여러 번 눌림 방지하는 실무 패턴 정리 🚫🔄 (0) | 2025.03.17 |
| React useEffect를 활용한 예약 시스템 데이터 관리 (4) | 2025.02.20 |
| CSS로 예약 불가 슬롯에 X자 표시하기 x배너 꾸미기 [React] (2) | 2025.02.20 |