carousel

sorin44·2022년 6월 5일
0
post-thumbnail

carousel

1차 프로젝트를 진행하면서 나는 메인페이지를 맡았는데 carousel을 진행해야했다. 라이브러리를 사용이 금지되어 직접 작성하려니 어떻게 진행해야할지 감이 안와 동기분들께 물어보니 각자 알고 계신 사이트를 알려줬다. 프로젝트 진행중에는 페이지를 완성하느라 이해하기 어려웠으나 정리가 필요하다는 생각이 들었다.

코드

css

처음 carousel을 만들 때 css에서 컴포넌트의 최상단 container에 overflow: hidden을 적용해줘야 선을 넘어간 이미지들은 보이지 않도록 처리 할 수 있다.
그리고 넘어 가야하는 사진들을 가로로 나열하기 위해 사진을 감싸는 div도 display: flex를 적용한다.

useState, useEffect, useRef

useEffect?
리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook입니다.

useRef?
useRef Hook은 함수 컴포넌트에서 ref를 쉽게 사용할 수 있도록 해줍니다. 대부분의 경우 상태가 변할 때 마다 react 컴포넌트 함수가 호출되어 화면이 갱신되기를 바랍니다. 하지만 그에 따른 부작용으로 함수 내부의 변수들이 기존에 저장하고 있는 값들을 잃어버리고 초기화되는데요. 간혹 다시 렌더링이 되더라도 기존에 참조하고 있던 컴포넌트 함수 내의 값이 그대로 보존되야 하는 경우가 있습니다.
useRef 함수는 current 속성을 가지고 있는 객체를 반환하는데, 인자로 넘어온 초기값을 current 속성에 할당합니다. 이 current 속성은 값을 변경해도 상태를 변경할 때 처럼 React 컴포넌트가 다시 랜더링되지 않습니다. React 컴포넌트가 다시 랜더링될 때도 마찬가지로 이 current 속성의 값이 유실되지 않습니다.

코드 적용

데이터를 불러오기 위해 useState 선언 후 useEffect를 이용한다.

  const [sources, setSources] = useState([]);

  useEffect(() => {
    fetch('data/womanProductCarousel.json', {
      method: 'GET',
    })
      .then(res => res.json())
      .then(data => {
        setSources(data);
      });
  }, []);

슬라이드의 초기값을 0으로 설정하고 넘어가는 페이지가 4페이지로 진행할 예정이라 TOTAL_SLIDES 를 3으로 지정해준다.

const [currentSlide, setCurrentSlide] = useState(0);
...
const TOTAL_SLIDES = 3;
...

useRef Hook을 이용하여 slide 한 번 넘어갈 때 currentSlide 한 번에 넘어 갈수 있도록 useEffect를 사용하고 함수를 선언하여 다음 버튼 이전 버튼의 onClick 함수를 사용하면 작동 할 수 있도록 한다.

  useEffect(() => {
    slideRef.current.style.transition = 'all 0.5s ease-in-out';
    slideRef.current.style.transform = `translateX(-${currentSlide}00%)`;
  }, [currentSlide]);
...
  const nextSlide = () => {
    if (currentSlide >= TOTAL_SLIDES) {
      setCurrentSlide(0);
    } else {
      setCurrentSlide(currentSlide + 1);
    }
  };

  const prevSlide = () => {
    if (currentSlide === 0) {
      setCurrentSlide(TOTAL_SLIDES);
    } else {
      setCurrentSlide(currentSlide - 1);
    }
  };
...
	<button type="button" className="carouselArrowLeft" onClick={prevSlide}>
        <FaArrowLeft />
      </button>
...
      <button type="button" className="carouselArrowRight" onClick={nextSlide}>
        <FaArrowRight />
      </button>
...

carousel indicator가 작동할 수 있도록 위에서 사용한 setCurrentSlide에 값이 저장할 수 있도록 함수를 선언한다.
이 함수에 빈 배열을 선언하여 (Array.from({ length: 4})에 map method를 사용한다. 이 때 감싸고 있는 div에서 onClick 이벤트가 발생하면 css로 만들었던 원형 모양 안에 검은 색으로 안쪽이 칠해지게 설정하고 화살표 버튼을 눌러도 검은색 원이 칠해 질 수 있도록 해준다.

...
react

      <div className="containerDots">
        {Array.from({ length: 4 }).map((_, index) => (
          <div
            key={index}
            onClick={() => moveDot(index)}
            className={currentSlide === index ? 'dot active' : 'dot'}
          />
        ))}
      </div>
...
scss
...
  .containerDots {
    position: absolute;
    bottom: 4rem;
    left: 50%;
    transform: translateX(-50%);
    display: flex;


  .dot {
    width: 1rem;
    height: 1rem;
    border-radius: 50%;
    border: 0.188rem solid #f1f1f1;
    margin: 0 5px;
    background: #f1f1f1;
  }

  .dot.active {
    background: rgb(32, 32, 32);
  }
}
...

Array.from()

Array.from() 메서드는 유사 배열 객체(array-like object)나 반복 가능한 객체(iterable object)를 얕게 복사해 새로운Array 객체를 만듭니다.

ex)

Array.from('foo');
// ["f", "o", "o"]

최종 화면

느낀점

carousel 을 직접 만드는게 엄청 어렵다는 생각이 들었다. 이번 프로젝트를 진행하면서 이 부분을 적용하는데 며칠이 걸렸고 기능 구현도 문제였지만 css를 맞춰서 잘 넘어가는 것도 쉽지 않았다.
이제 점점 css가 어려워지고 있다...

참고 및 출처
https://github.com/Ziratsu/Slider-React
https://krpeppermint100.medium.com/js-react-hooks%EB%A1%9C-carousel-slider-%EB%A7%8C%EB%93%A4%EA%B8%B0-2e558151bbee
리액트를 다루는 기술 책
https://www.daleseo.com/react-hooks-use-ref/
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/from

profile
프론트엔드 개발자입니다.

0개의 댓글