[JULABO] React.js로 Infinite Carousel 구현 (라이브러리 미사용)

윤남주·2022년 2월 6일
7

첫 번째 프로젝트에서 나는 메인페이지와 상품 리스트 페이지를 담당하였다.
메인 페이지는 솔직히 마음은 편하다. 왜냐면 백엔드에서 받아올 데이터가 하나도 없고, 그냥 나만 잘 하면 되기 때문에.
하지만 그런만큼 구현해야하는 UI 컴포넌트들이 많았고, 인터랙티브한 UI 컴포넌트가 많았다.
이를 때깔 좋게, 잘 만드는 것이 내 임무...🧑‍💻

다른 것들은 괜찮았는데, 제일 오래 걸리고 골치 아팠던 것이 무한 캐러셀(마지막에서 첫번째로 다시 이동하는 것이, 그냥 오른쪽으로 넘어가는 것 처럼 보이게 만드는 슬라이더)였다.

이 블로그 포스팅을 참고 많이 하고, 실제로 이 포스팅을 보고나서야만 구현할 수 있었다. 링크를 달며 감사의 말씀까지 전하고 싶다 🙏😇


구현 방식

기본 캐러셀은 이렇게 구동된다!

  1. 이미지 wrapper를 하나 만들어서 그 영역에 overflow: hidden;을 준다
  2. 그리고 원하는 이미지들을 wrapper에 딱 들어가도록, 그리고 수평 정렬되도록 만든다.
    flex flex-shrink flex-wrap 등을 사용
  3. 그리고 마지막으로 이미지들 전체를 감싸고 있는 div를 transform: translateX(값)로 움직여줌
    버튼에 따라서 translate 값을 state로 관리한다!

무한 슬라이드는 이렇게 만들었다!

  1. 원래 배열의 양 옆에 눈속임 슬라이드를 만든다
  2. 슬라이딩을 계속하며 마지막 슬라이드 (혹은 0번째 슬라이드)에 다다르면...
  3. transition이 끝난 후, transition을 제거하고, 1번 슬라이드(혹은 n-1번째 슬라이드)로 이동!!
  4. 그러면 진짜 무한슬라이드가 되는 마냥 보인다... ✨😇


실제 코드

로직 파트

1️⃣ State는 두 가지 ✌️

const [currCarousel, setCurrCarousel] = useState(1);
const [carouselTransition, setCarouselTransition] = useState('transform 500ms ease-in-out');

currCarousel은 현재 보여져야할 캐러셀을 나타내며, 초기값은 1번 슬라이드이다.
carouselTransition은 carousel 컴포넌트에 적용된 인라인 스타일이다.
(인라인 스타일을 쓰고싶지 않았지만... 정말 다른 방법은 생각이 안났다. styled-component도 사용 못하고 🥺)


2️⃣ 함수는 네 가지나...

const makeNewDataArray = arr => {
  const dataStart = arr[0];
  const dataEnd = arr[arr.length - 1];
  const modifiedArray = [dataEnd, ...arr, dataStart];
  return modifiedArray;
};

const slideNextSoulsCarousel = () => {
  const soulSliderLength = SOUL_DATA.length;
  const newCurr = currCarousel + 1;
  setCurrCarousel(newCurr);

  if (newCurr === soulSliderLength + 1) {
    moveToNthSlide(1);
  }

  setCarouselTransition('transform 500ms ease-in-out');
};

const slidePrevSoulsCarousel = () => {
  const soulSliderLength = SOUL_DATA.length;
  const newCurr = currCarousel - 1;
  setCurrCarousel(newCurr);

  if (newCurr === 0) {
    moveToNthSlide(soulSliderLength);
  }
  
  setCarouselTransition('transform 500ms ease-in-out');
};

const moveToNthSlide = n => {
  setTimeout(() => {
    setCarouselTransition('');
    setCurrCarousel(n);
  }, 500);
};

makeNewDataArray(arr)
원래 배열에서 앞에는 맨 마지막 슬라이드를 복제, 뒤에는 맨 첫번째 슬라이드를 복제하는 함수

slideNextSoulsCarousel()
slidePrevSoulsCarousel()
다음 슬라이드, 이전 슬라이드 버튼 onClick의 동작 함수.
➕ 맨 마지막 슬라이드 or 맨 처음 슬라이드에서 더 갈 경우에 moveToNthSlide 함수를 실행시킴

moveToNthSlide(n)
n번째 슬라이드로 이동하는 함수.
하지만 그냥 이동하지 않고 transition이 일어나기까지 기다렸다가
→ transition을 모두 지워주고
→ 캐러셀 이동을 한다
🤯🤯🤯🤯🤯🤯


렌더링 파트

transform에는 translateX 값이 들어감 (currCarousel state값에 따라 이동을 하게 됨)
transition 또한 인라인 스타일로 들어가며, 위 함수들에 의해 변경됐다 안됐다

<div
  className="carouselImageWrap" key={index}
  style={{
    transform: `translateX(-${currCarousel * 100}%)`,
    transition: `${carouselTransition}`,
  }}
>
  <img memo="원하는 이미지들이 들어감..."/>
</div>

작동 모습

귀여운 우리 팀원들의 모습이 들어있기 때문에, 삭제할 수도 있습니다 🧠👀

profile
Dig a little deeper

1개의 댓글

comment-user-thumbnail
2023년 8월 29일

transition: ${carouselTransition}
이부분은
transition : carouselTransition 으로 사용하는게 깔끔하지 않을까요?

좋은 글 감사합니다!

답글 달기