From a43b6a0ed0f0b2c6ee1165c7d598bdc29d336d9d Mon Sep 17 00:00:00 2001 From: jam-jang Date: Fri, 22 Aug 2025 10:05:45 +0900 Subject: [PATCH] final --- src/components/CategorySlider.tsx | 58 +++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/src/components/CategorySlider.tsx b/src/components/CategorySlider.tsx index 7693e05..f331a5e 100644 --- a/src/components/CategorySlider.tsx +++ b/src/components/CategorySlider.tsx @@ -1,5 +1,5 @@ // src/components/CategorySlider.tsx -import React, { useEffect, useMemo, useRef } from 'react'; +import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react'; import { Swiper, SwiperSlide } from 'swiper/react'; import type { Swiper as SwiperCore } from 'swiper'; import 'swiper/css'; @@ -18,18 +18,48 @@ export default function CategorySlider({ }: CategorySliderProps) { const swiperRef = useRef(null); - // 현재 선택된 카테고리의 인덱스 계산 + // 드래그와 클릭 구분용 플래그 + const [isDragging, setIsDragging] = useState(false); + const dragTimerRef = useRef(null); + + const setDraggingSafely = useCallback((val: boolean) => { + setIsDragging(val); + if (dragTimerRef.current) { + window.clearTimeout(dragTimerRef.current); + dragTimerRef.current = null; + } + if (!val) return; + // 드래그 종료 후 아주 짧게만 드래그 상태 유지했다가 해제 + dragTimerRef.current = window.setTimeout(() => { + setIsDragging(false); + dragTimerRef.current = null; + }, 80); + }, []); + + // 현재 선택된 카테고리의 인덱스 계산 (컨트롤드) const selectedIndex = useMemo(() => { - const idx = categories.findIndex(c => c.label === selectedCategory); + const idx = categories.findIndex((c) => c.label === selectedCategory); return idx >= 0 ? idx : 0; }, [categories, selectedCategory]); - // 선택 변경 시 해당 슬라이드로 이동 + // 선택 변경 시 해당 슬라이드로 이동 (애니메이션 0으로 튀는 문제 방지 위해 살짝만) useEffect(() => { if (!swiperRef.current) return; - swiperRef.current.slideTo(selectedIndex, 0); + // 이미 그 위치면 noop + if (swiperRef.current.activeIndex !== selectedIndex) { + swiperRef.current.slideTo(selectedIndex, 150); // 0 -> 150ms로 부드럽게 + } }, [selectedIndex]); + // 클릭 핸들러 (드래그 중 클릭 무시) + const handleClick = useCallback( + (label: string) => { + if (isDragging) return; + onSelect(label); // ← 즉시 1회 호출 (컨트롤드 상위에서 상태/URL 동기화) + }, + [isDragging, onSelect] + ); + return (
(swiperRef.current = swiper)} + // 드래그 감지 + onTouchMove={() => setDraggingSafely(true)} + onTouchEnd={() => setDraggingSafely(false)} + onSliderFirstMove={() => setDraggingSafely(true)} + onTransitionEnd={() => setDraggingSafely(false)} > {categories.map((category) => ( - + ))}