-
react-slick 캐러셀 Prev, Next Arrow 버튼 더블 클릭 버그Studying/React 2023. 8. 20. 21:48
문제 발생
PortfolioItem.tsx 컴포넌트의 캐러셀에서 Prev/Next 버튼에 더블 클릭이 적용되지 않는 문제가 발생했습니다. 여러번 빠르게 클릭한 만큼 캐러셀이 빠르게 넘어가지 않습니다.
사용한 캐러셀 라이브러리는 react-slick 입니다.
캐러셀 맨 처음 페이지, 맨 끝 페이지에 도달했을 때 각각 Prev, Next 버튼이 보이지 않도록 만들기 위해 캐러셀의 인덱스를 파악해야 했고, 이를 useState로 관리했습니다.const [currentSlideIndex, setCurrentSlideIndex] = useState(0);
Prev 버튼 클릭 시 prev - 1 Next 버튼 클릭 시 prev + 1 되어 페이지가 증가/감소합니다.
버튼을 빠르게 클릭한 만큼 currentSlideIndex는 증감하는데, 캐러셀은 덜 넘어가고, 현재 캐러셀 인덱스와 currentSlideIndex가 불일치하는 문제가 발생합니다.정상 화면이라면 다음과 같아야합니다.
하지만 현재 문제 화면은 다음과 같습니다.
3 페이지에서 Prev 버튼을 빠르게 2번 클릭하면 index -1 연산이 두 번 수행되어 currentSlideIndex는 0이 됩니다. 따라서 Prev 버튼이 사라집니다.
하지만 캐러셀은 한 페이지만 넘어가느라 아직 2 페이지고, 1페이지로 갈 수 없게됩니다.전체 코드는 다음과 같습니다.
// PortfolioItem.tsx // 현재 인덱스 const [currentSlideIndex, setCurrentSlideIndex] = useState(0); // PrevArrow 컴포넌트 onClick 함수 const handlePrevious = (button:HTMLButtonElement) => { setCurrentSlideIndex((prev) => prev - 1); // 인덱스 1 감소 slick?.slickPrev(); // 이전 페이지로 이동 } // NextArrow 컴포넌트 onClick 함수 const handleNext = (button:HTMLButtonElement) => { setCurrentSlideIndex((prev) => prev + 1); // 인덱스 1 증가 slick?.slickNext(); // 다음 페이지로 이동 }
원인
react-slick은 캐러셀이 넘어가는 속도인 speed 값이 기본값 500ms으로 제공되기 때문에 발생한 문제였습니다.
따라서 speed: 0 으로 설정하면 클릭 속도에 맞춰 캐러셀이 넘어갑니다.
하지만 부드러운 움직임을 유지하고 싶을 경우, 캐러셀이 speed 시간 동안 다 움직이고 정지한 다음에 Prev/Next 버튼이 활성화돼야 합니다.해결 방법
1. lodash의 throttle을 사용하기
throttle을 사용하여 캐러셀 speed 시간 당 한 번 이벤트가 발생하도록 조정할 수 있습니다.
하지만 현재 코드의 경우, handlePrev()/handleNext() 함수 안에 <Slider>를 참조하는 slick이 존재합니다.
throttle을 쓸 경우 리렌더링 되어도 (과거에 계속 호출된) 자기 자신을 기억하기 위해 useCallback을 쓰고 초기화 옵션으로 [](초기 렌더링 때 한 번 초기화)를 지정해야 합니다.
하지만 throttle 함수가 정의되는 첫 순간에는 아직 DOM이 형성되지 않아 slick이 존재하지 않습니다. 따라서 결국 캐러셀을 넘기지 못하게 되는 겁니다.2. 직접적으로 핸들러 막기
결국 무식한 방법으로 문제를 해결했습니다.
const [currentSlideIndex, setCurrentSlideIndex] = useState(0); // 현제 캐러셀 인덱스 const [beforeClicked, setBeforeClicked] = useState(false); // 직전에 버튼이 클릭되었는지 여부 const [slick, setSlick] = useState<Slider>(); // 캐러셀 컴포넌트 <Slider> const handlePrev = ()=> { if(beforeClicked) return; // 바로 직전에 버튼 클릭했으면 핸들러 작동 x early return setBeforeClicked((prev)=>!prev); // 그게 아니면 버튼이 정상적으로 눌린 게 되고 true로 바꿈 slick?.slickPrev(); // 이전 페이지로 이동 setCurrentSlideIndex((prev) => prev - 1); // 인덱스 1 감소 setTimeout(()=>setBeforeClicked((prev)=>!prev), 200); // 캐러셀이 넘어가는 시간(speed)인 200ms가 지나면 다시 버튼 활성화되도록 false로 바꿔줌 }; const handleNext = ()=> { if(beforeClicked) return; setBeforeClicked((prev)=>!prev); slick?.slickNext(); setCurrentSlideIndex((prev) => prev + 1); setTimeout(()=>setBeforeClicked((prev)=>!prev), 200); };
결과는 딱 원하는대로 나왔습니다.
Next 버튼을 더블 클릭했을 때, 첫 번째 클릭한 순간 캐러셀 이동, 인덱스 +1 증가. 두 번째 클릭은 반영되지 않습니다.
단점은 해석이 불편한 코드가 되었다는 점 같습니다3. 클릭 횟수만큼 빠르게 넘기기가 가능한 캐러셀 라이브러리를 설치하자.
제 기억에 부트스트랩도 그렇고 다양한 좋은 캐러셀 라이브러리가 많았습니다.
하필 react-slick을 처음 써보려고 할 때 이런 문제같지 않은 문제가 발생하네요.
당장 가진 환경에서 문제를 해결하고싶다는 오기로 인해 시도하진 않았지만 가장 현명한 방법 같습니다.
참고 사이트
'Studying > React' 카테고리의 다른 글