현재 협업 중인 사이드 프로젝트에서는 쉽고 간편한 검색과 다양한 추천 서비스를 제공하는 OTT 정보 플랫폼 서비스의 프론트엔드(FE) 개발을 진행하고 있습니다. 사용자에게 최적의 경험을 제공하기 위해 일관된 UI 컴포넌트와 효율적인 코드 구조를 구축하는 것을 목표로 합니다. 이를 위해 프론트엔드 팀원(저를 포함해 3명)분들과 함께 공통으로 사용할 UI 컴포넌트를 개발하고 있습니다.
슬라이더 드래그 동작 중 의도치 않게 링크가 활성화되어 상세 페이지로 이동하는 현상이었습니다. 구체적으로, 사용자가 슬라이드를 드래그할 때 슬라이드 내부의 Link 컴포넌트가 클릭 이벤트로 인식되어 원치 않는 페이지 전환이 발생했습니다.
이는 드래그 제스처와 클릭 이벤트가 동시에 발생하면서 생기는 문제로, 사용자 경험을 크게 저해하는 핵심 이슈였습니다. 특히 슬라이더에서의 드래그는 콘텐츠 탐색을 위한 필수적인 인터랙션이기에, 이 과정에서 발생하는 의도치 않은 페이지 전환은 사용자의 몰입을 방해하는 심각한 UX 저하 요인이었습니다.
Link
컴포넌트가 클릭 이벤트를 감지하여 발생하는 것이었습니다. 따라서 해결 방향을 '드래그와 클릭 동작의 명확한 구분'으로 설정했습니다.마우스 이벤트를 활용한 드래그 감지 로직을 구현하기로 결정했습니다. 구체적으로 다음과 같은 이벤트 핸들러를 구현했습니다:
onMouseDown
: 드래그 시작점 좌표 저장
onMouseMove
: 실시간 이동 거리 계산 및 드래그 상태 판단
onMouseUp
: 드래그 종료 및 최종 동작 판단 (드래그 vs 클릭)
// 중략
const SectionSlider: React.FC<SectionSliderProps> = ({
sectionSlides,
showActionBar,
}) => {
const [isDragging, setIsDragging] = useState(false);
const [startX, setStartX] = useState(0);
const handleMouseDown = (e: React.MouseEvent) => {
setIsDragging(false);
setStartX(e.clientX);
};
const handleMouseMove = (e: React.MouseEvent) => {
if (e.buttons !== 1) return; // 마우스 왼쪽 버튼이 눌려 있지 않으면 종료
const moveX = Math.abs(e.clientX - startX);
if (moveX > 5) { // 드래그 거리가 5px 이상이면 드래그로 인식
setIsDragging(true);
}
};
const handleMouseUp = () => {
// 드래그가 끝났으므로 상태를 false로 변경
setTimeout(() => {
setIsDragging(false);
}, 50);
};
const settings = {
infinite: true,
speed: 500,
slidesToShow: 8,
slidesToScroll: 1,
swipeToSlide: true,
};
return (
<div className={styles.container}>
<div className={`${styles.slider} section-slider`}>
<Slider {...settings}>
{sectionSlides.map((sectionSlide, index) => (
<div
key={index}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
>
<Link
href={sectionSlide.detailUrl}
className={styles.cardLink}
onClick={(e) => {
// 드래그 중일 때만 클릭 이벤트 방지
if (isDragging) {
e.preventDefault();
}
}}
>
/* 중략 */
</Link>
</div>
))}
</Slider>
</div>
</div>
);
};
export default SectionSlider;