<aside> 💡 API 연결 없이 임시 데이터로 화면만 구현했습니다
</aside>
모바일 기기일 때와 아닐 때에 event가 다르기 때문에 구분해주어야 한다. 아래 코드는 웹 기준으로 작성했다.
const isTouchScreen =
typeof window !== "undefined" && window.matchMedia("(hover: none) and (pointer: coarse)").matches;
사용자가 마우스를 눌렀을 때
isDragging의 값을 true로 바꾼다.positionYRef에 저장한다.
useState를 사용했을 경우엔 리렌더링이 일어나기 때문에 리렌더링 없이 값을 관리할 수 있는 useRef를 대신 사용했다.const handleMouseDown = (clickEvent) => {
clickEvent.preventDefault();
const carouselItems = carouselItemsRef.current;
// a
setIsDragging(true);
// b
positionYRef.current = clickEvent.pageY;
// c
window.addEventListener("mousemove", handleMouseMove);
carouselItems?.addEventListener("mouseup", handleMouseUp, { once: true });
};
사용자의 마우스가 움직이는 동안
deltaY 변수를 만들었다.transY state에 저장한다.const handleMouseMove = (moveEvent) => {
// a
const deltaY = positionYRef.current - moveEvent.pageY;
// b
if (moveEvent.clientY > ITEM_HEIGHT || moveEvent.clientY < 0) {
window.removeEventListener("mousemove", handleMouseMove);
setTransY(0);
setIsDragging(false);
return;
}
// c
setTransY(inRange(deltaY, -ITEM_HEIGHT, ITEM_HEIGHT));
};
사용자가 마우스를 뗐을 때
const handleMouseUp = (moveEvent) => {
const deltaY = positionYRef.current - moveEvent.pageY;
// a
let nextIndex = currentIndex;
// b
if (deltaY < -150) {
nextIndex = inRange(currentIndex - 1, 0, maxLen - 1);
setCurrentIndex(nextIndex);
}
if (deltaY > 150) {
nextIndex = inRange(currentIndex + 1, 0, maxLen - 1);
setCurrentIndex(inRange(nextIndex));
}
// c
setTransY(0);
setIsDragging(false);
// d
if (currentIndex !== nextIndex) {
console.log(currentIndex, "번 쇼츠 ", (new Date() - startTime) / 1000, "초 봤음");
setStartTime(new Date());
}
window.removeEventListener("mousemove", handleMouseMove);
};
모바일에서도 동작은 비슷하나 event를 touchstart touchmove touchend 로 등록했다.
useEffect(() => {
maxLen.current = shortList.length;
}, [shortList.length]);
useEffect(() => {
setStartTime(new Date());
}, [currentIndex]);