React 가로 스크롤 - React galo seukeulol

  • 가로 스크롤을 가능하게 해주는 짱 멋진 모듈을 발견했다.
    <div>로 이루어진 각각의 요소들을 일렬로 나열해서 마우스 휠을 움직이면 좌우로 스크롤이 가능하다. 데모 영상에서 볼 수 있듯이 풀 스크린도 가능하고, width 조절을 통해 폭을 조절할 수도 있다.

1. 사용 계기

  • 웹페이지 개발 과정에서 디자이너 친구가 요즘은 풀 스크린이 유행이라는 새로운 사실을 알려주었다. 그래서 현재 모든 페이지들을 전체 화면 크기는 고정시켜두고, 가로로 스크롤하는 형식으로 만들어 나가고 있다. 그 중 첫 번째 도전이 랜딩페이지의 동영상들을 가로 스크롤을 통해 로드할 수 있도록 하는 것이었다. 구글링해본 결과 'react-scroll-horizontal' 모듈이 우리가 원하는 방식과 정확히 일치해서 사용하게 되었다. (。・∀・)ノ

2. 사용 방법

  • 설치
    npm i react-scroll-horizontal
  • 적용
    import ScrollHorizontal from 'react-scroll-horizontal';

    <div id='scroll-horizontal' style={{ height: `45em` }}>
        <ScrollHorizontal>
           {renderCards}
        </ScrollHorizontal>
    </div>

대략 위와 같은 방법으로 사용 가능하다.

중요한 부분은 {renderCards} 부분인데, renderCards의 자료형은 배열이며, 각각의 요소들은 <div> 태그로 감싸져 있는 형태이다. 즉 import 해 온 모듈 사이에 화면에 나타내고 싶은 요소들을 <div> 형태로 원하는 만큼 넣어주면 된다!


3. 에러 사항

1) 가져온 요소들의 크기가 불규칙하게 나타남

→ 요소들의 <div> 태그에 CSS width 속성을 px 단위로 고정해주는 방법을 통해 해결했다. % 단위가 아니기 때문에 화면이 작아졌을 때도 크기가 그대로라는 단점이 있지만 일단은 PC 버전이 제일 우선 순위이기 때문에 이렇게 적용했다. 반응형은 나중에 미디어 쿼리를 적용해봐야 할 것 같다.

2) 요소들을 두 줄로 로드하고 싶음

화면설계서상, 2XN 형태로 영상들을 로드해야했다. 대부분의 웹페이지는 세로 스크롤이다 보니, column의 개수를 고정하는 것은 어렵지 않았는데, row의 개수를 고정하는 것이 꽤 어려웠다.

→ 개발 팀원이 답을 찾아주었는데, 아래와 같이 CSS 속성을 설정해주는 방법으로 해결했다.

#scroll-horizontal .scroll-horizontal > div {
  display: grid !important;
  grid-template-rows : auto auto;
  grid-auto-flow: column;
}

우선 그리드 형태로 나타내주었다. 이때 !important 값을 넣어준 이유는 모듈 내부 파일의 display 속성과 충돌할 때, 현재 코드의 값을 더 우선적으로 적용하기 위해서이다. 현재 CSS 선택자가 모듈 내부 파일의 태그를 선택하고 있어서 display 속성이 서로 충돌하는 상태였다.

다음으로 grid-template-rows 속성으로 행의 개수를 설정해주었다. auto값은 행의 사이즈를 자동으로 지정해준다. 또한 auto가 두 개이므로 요소가 두 줄로 나타나게 된다! 예를 들어 세 줄로 나타내고 싶으면 grid-template-rows : auto auto auto; 라고 해주면 된다.

grid-auto-flow: column; 부분은 각 열을 차례로 채워가며 배치해주는 속성이라고 한다.

4. 결과물

대략 이런 프레임으로 만들어주었다. 😊

React 가로 스크롤 - React galo seukeulol


References

https://www.npmjs.com/package/react-scroll-horizontal
https://github.com/hew/react-scroll-horizontal

1. 구현하고자 한 것

스크롤바 기능은 하지만 보이지는 않게 하기

🤔 단순히 CSS 에서display:flex로 하면 안되나?

실패

React 가로 스크롤 - React galo seukeulol

모든 영화를 포함하고 있는 div에 styles를 적용해주어야 한다.

.moviesContainer {
  display: flex;
  overflow: auto;
  white-space: nowrap;
}

여기서 white-space는 CSS white-space 속성은 요소가 공백 문자를 처리하는 법을 지정한다.
이미지들의 나열이기 때문에 불필요하다고 판단해서 제거해 주었다.

👇 공식 문서 참고
https://developer.mozilla.org/ko/docs/Web/CSS/white-space

React 가로 스크롤 - React galo seukeulol

또 다른 문제점이 발생했다. 스크롤 바를 제거했더니 이미지가 넘어가지 않았다.

내가 원하는 것은 버튼을 누르면 옆에 넘어간 영화 이미지를 보여주는 것이었다.

✅ 구글링을 통해 이것을 캐로셀(Carousel) 이라고 부르는 것이 있다는 것을 알았다. 번역하면 회전목마 라고 한다!

이를 구현하기 위해서는 많은 라이버리가 있다고 하는데 나는 JS 실력 향상을 위해 javascript로 이를 구현해보고자 했다.

🎠 캐로셀 구현하기

🤔 어떻게 구현하면 좋을까?

일단 보여주고 싶은 이미지가 무엇인지 인덱스로 표현할 수 있겠다고 생각했다.

그러면 버튼을 눌를 때 마다 보여주고 싶은 인덱스만큼의 이미지만 보여주면 된다.

총 4개씩의 이미지를 보여주기로 했고, 이는 const에 담으면 될 것 같다.

todo list 만들기에서 버튼을 눌를 때마다 컴포넌트를 렌더링 해줄 때 useState를 사용했던 경험이 떠올라서
스크롤 버턴을 누르면 useState의 data를 이미지 인덱스 번호로 설정해서 렌더링이 이루어지면 좋겠다고 생각했다!

그럼 데이터를 저장했다가 버튼을 누르면 맨 왼쪽의 이미지는 사라지게 하고, 오른쪽의 이미지를 하나 생성하면서 보여지는 모든 이미지를 하나씩 왼쪽으로 이동하면 좋을 것 같았다.

🤔 이미지를 사라지게 만드는 방법?

🤔 이미지를 생성하는 방법?

이를 한번에 해결할 수 있는 화면 이동 속성 transform: translateX() 가 있었다.

👇 transform: translateX() 공식 문서

https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translateX

❗️ 이때 인덱스가 0보다 커져서 계속 왼쪽으로 이동하는 현상 발생!
-> if 문을 활용해서 return으로 더 이상 translate가 동작하지 못하도록 만들었다.

import React, { useEffect, useState } from "react";
import Movie from "../component/Movie";
import styles from "./Home.module.css";
function Home() {
 const [loading, setLoading] = useState(true);
 const [movieData, setMovieData] = useState([]);
 const [moveIndex, setMoveIndex] = useState(0);
 const leftMove = () => {
   if (moveIndex === 0) {
     return;
   }
   setMoveIndex((prev) => prev + 10);
 };

 const rightMove = () => {
   setMoveIndex((prev) => prev - 10);
 };
 const getMovies = async () => {
   const json = await (
     await fetch(
       `https://yts.mx/api/v2/list_movies.json?minimun_rating=9&sort_by=year`
     )
   ).json();
   setMovieData(json.data.movies);
   setLoading(false);
 };

 useEffect(() => {
   getMovies();
 }, []);
 console.log(moveIndex);
 return (
   <div>
     {loading ? (
       <h2>loading</h2>
     ) : (
       <div>
         <button onClick={leftMove}>left</button>
         <button onClick={rightMove}>right</button>

         <div
           className={styles.moviesContainer}
           style={{ transform: `translateX(${moveIndex}%)` }}
         >
           {movieData.map((movie) => (
             <div className={styles.transform}>
               <Movie
                 key={movie.id}
                 id={movie.id}
                 coverImg={movie.medium_cover_image}
                 title={movie.title}
                 summary={movie.summary}
                 genres={movie.genres}
               />
             </div>
           ))}
         </div>
       </div>
     )}
   </div>
 );
}

export default Home;

🎉 완성!

아직 css 작업과 index 를 화면 크기에 맞춰서 조정해주어야 하지만 전체적 로직은 모두 구현하였다!!! 기쁘다!!!

React 가로 스크롤 - React galo seukeulol