React 웹 환경에서 세로 스크롤은 스크롤바 말고도 마우스 휠로 화면을 스크롤 할 수 있어서 불편함이 없지만 가로 스크롤의 경우 스크롤바로 스크롤 하는게 편하지는 않습니다. 그래서 모바일 환경에서 처럼 마우스 클릭 후 드레그로 좌우 스크롤이 가능 하도록 구현 해 보도록 하겠습니다.
1. 기본 화면 구성
먼저 스크롤 기능을 적용할 페이지를 만들어 보도록 하겠습니다.
index.js
import styles from '@/styles/Home.module.css'
import React, { useEffect} from 'react'
export default function Home() {
const list = ["1번","2번","3번","4번","5번","6번","7번","8번","9번","10번"]
return (
<>
<main >
<div>
{list && (
<div className={styles.list}>
{
list.map((item, index) => (
<div className={styles.item} key={index}
onClick={() => {
isDrag ? null : console.log(`${index}번 클릭입니다`)
}}>
<p>{item}</p>
</div>
))
}
</div>
)}
</div>
</main>
</>
)
}
Home.module.css
.list {
display: flex;
min-width : 100%;
flex-direction: row;
overflow: hidden;
align-items: center;
overflow-x: auto;
}
.list::-webkit-scrollbar {
display: none;
}
.item{
flex-shrink: 0;
width: 100px;
height: 300px;
margin-right: 5px;
background-color: aquamarine;
}
2. UseRef 활용
가로 스크롤에 드래그 이벤트를 달기 위해선 먼저 스크롤 영역의 document에 접근 할 수 있도록 useRef 선언하후 스크롤 영역을 지정 해 줍니다.
import React, { useRef, useState } from 'react'
export default function Home() {
...
const scrollRef = useRef(null);
...
<div className={styles.list} ref={scrollRef}>
3. 이벤트 핸들러 작성
드레그 한 만큼 스크롤의 left 이동 하기 위해 총 3가지 이벤트 리스너를 등록해 줍니다
먼저 필요한 state를 추가해 주겠습니다.
const [isDrag, setIsDrag] = useState(false);
const [start, setStart] = useState("");
그 다음 마우스를 눌렀을 때 x 값을 구해 줍니다.
const onMouseDown = (event) => {
event.preventDefault();
setIsDrag(true);
setStart(event.pageX + scrollRef.current.scrollLeft);
};
그리고 마우스를 드래그 할 때 스크롤을 움직여 줍니다. 마우스를 누른 후 움직일 때만 작동하도록 flag를 달아 주겠습니다.
const onDragMove = (event) => {
if (isDrag) {
scrollRef.current.scrollLeft = start - event.pageX;
}
};
마지막으로 마우스를 뗄 때 입니다.
const onMouseUp = (event) => {
setIsDrag(false);
};
4. 이벤트 리스너 등록
작성한 핸들러를 스크롤을 작동시킬 영역에 이벤트 리스너로 달아 주겠습니다. onMouseDown, onMouseMove, onMouseUp 이벤트에 각각 대응되는 핸들러들을 달아 주고 추가로 드레그 중 스크롤 영역을 벗어나면 드래그를 종료 하게끔 onMouseLeave 이벤트에도 드래그 종료 핸들러를 달아 주겠습니다.
<div className={styles.list}
onMouseDown={onMouseDown}
onMouseMove={isDrag ? onDragMove : null}
onMouseUp={onMouseUp}
onMouseLeave={onMouseUp}
ref={scrollRef}
>
5. 예외처리
마지막으로 드래그 중에는 가로 스크롤 영역 내부 contents에 click 이벤트가 발생하지 않도록 flag를 달아 주도록 하겠습니다.
<div className={styles.item} key={index}
onClick={() => {
isDrag ? null : console.log(`${index}번 클릭입니다`)
}}>
6. 최종 script 코드
import styles from '@/styles/Home.module.css'
import React, { useEffect, useRef, useState } from 'react'
export default function Home() {
const list = ["1번","2번","3번","4번","5번","6번","7번","8번","9번","10번"]
const scrollRef = useRef(null);;
const [isDrag, setIsDrag] = useState(false);
const [start, setStart] = useState("");
const onMouseDown = (event) => {
event.preventDefault();
setIsDrag(true);
setStart(event.pageX + scrollRef.current.scrollLeft);
};
const onMouseUp = (event) => {
setIsDrag(false);
};
const onDragMove = (event) => {
if (isDrag) {
scrollRef.current.scrollLeft = start - event.pageX;
}
};
return (
<>
<main >
<div>
{list && (
<div className={styles.list}
onMouseDown={onMouseDown}
onMouseMove={isDrag ? onDragMove : null}
onMouseUp={onMouseUp}
onMouseLeave={onMouseUp}
ref={scrollRef}>
{
list.map((item, index) => (
<div className={styles.item} key={index}
onClick={() => {
isDrag ? null : console.log(`${index}번 클릭입니다`)
}}>
<p>{item}</p>
</div>
))
}
</div>
)}
</div>
</main>
</>
)
}
7. 마무리
이상으로 react 가로 드래그 스크롤 구현을 마무리 하도록 하겠습니다. 물론 찾아보면 가로 드래그 스크롤 plugin이 존재 합니다만 개인적으로는 간단한 단위의 component는 직접 구현해서 사용하는게 좋다고 생각합니다. 이보다 좋은 방법이 있거나 잘못된 부분, 혹은 개선 했으면 하는 부분은 공유 해 주시면 참고하여 수정하도록 하겠습니다.
'React' 카테고리의 다른 글
[React] infinite scroll(무한 스크롤) 구현 - Intersection Observer (0) | 2023.06.07 |
---|---|
[React] infinite scroll(무한 스크롤) 구현 - scroll event (0) | 2023.05.31 |
[React] useMemo 사용법 및 예제, 변수 재사용 - react hook (0) | 2023.05.29 |
[React] 웹에서 가로 터치 스크롤 만들기-컴포넌트 만들기(2/2) (0) | 2023.05.21 |
React를 해야 하는 이유, 특징 및 장단점 (0) | 2023.04.11 |