infinite carousel

jiseong·2022년 2월 3일
0

T I Learned

목록 보기
174/291

슬라이더를 움직임일 때 현재 슬라이더 위치를 표현하기 위해 curIdx를 사용하였고 transform: translateX() 속성을 이용하여 슬라이더를 이동시켰다. (margin-left 속성등으로도 이동 가능)

const [curIdx, setCurIdx] = useState(0);


const CarouselRow = styled.section<{ moveX: number; transitionEffect: string }>`
  position: relative;
  transform: ${({ moveX }) => `translateX(calc(${moveX}%))`};
`;

이전에 구현했던 carousel과는 다르게 현재 슬라이더는 화면 정 중앙에 위치해야하고 좌우에는 다음 슬라이더들이 보여야한다.

해당 조건들을 만족시키기 위해서 우선 슬라이더 행을 left: 50%을 주어 화면에 중앙부터 시작하게 하였다.

const CarouselRow = styled.section<{ moveX: number; transitionEffect: string }>`
  display: flex;
  left: 50%;
`;

그리고 우리가 어떤 요소를 가운데 위치시키기 위한 방법 중 하나인 left: 50%; transfrom: translateX(-50%)와 같은 방식을 사용하여 carousel를 이동시켜줘야 한다.

이를 구현하기 위해 위에서 사용했던 현재 슬라이더의 위치인 curIdx값을 이용하여 현재 슬라이더 위치만큼 %를 이동하고 그 다음 중앙에 위치하기 위해 슬라이더의 절반만큼을 더 이동하면 다음 슬라이더를 이동하여 현재의 슬라이더를 가운데 위치시킬 수 있다.

<CarouselRow
  moveX={(-100 / paddedItems.length) * (curIdx + 0.5)}
  >
  // 생략...
</CarouselRow>


const CarouselRow = styled.section<{ moveX: number; transitionEffect: string }>`
  position: relative;
  display: flex;
  left: 50%;
  width: fit-content;
  transform: ${({ moveX }) => `translateX(calc(${moveX}%))`};
`;

처음에는 아래 사진과 같이 이전에 사용했던 방식을 사용했었다.

하지만 문제점이 있었는데 이번 carousel는 좌우에는 다음 슬라이더가 보이다보니 마지막 요소에서 넘어갈 때 임시적으로 만든 복사본 슬라이더의 옆이 비어있다가 나타나는 현상이 발생하게 되었다.

해당 문제는 좌우에 2개씩 복사본을 만들어 놓음으로써 해결할 수 있었다.

추가적인 기능

매직넘버

코드를 작성하고 나중에 돌이켜보면 해당 숫자가 의미하는 바를 까먹을 때가 많았다. 그런 것들을 방지하고자 이번에는 상수들을 모아놓아 폴더를 만들게 되었다.

const CAROUSEL = {
  PADDING_DATA: 2,
  PADDING: 80,
  TRANSITION_TIME: 500,
  HANDLE_TYPE: {
    PREV: -1,
    NEXT: 1,
  },
  ITEM_MAX_WIDTH: 1250,
  ITEM_MIN_WIDTH: 560,
};

export { CAROUSEL };

반응형 및 throttle

화면의 크기의 변화에 슬라이더 크기도 맞추기 위해 반응형으로 동작하기 위해 슬라이더 너비값을 state로 두어 윈도우 사이즈가 변할 때마다 리렌더링이 될 수 있도록 했다.

(해당 과정에서 Lazy initial state을 새롭게 알게되었음)

  const [windowWidth] = useWindowSize();

  const [itemWidth, setItemWidth] = useState(() =>
    calcWidth(
      windowWidth,
      CAROUSEL.PADDING,
      CAROUSEL.ITEM_MIN_WIDTH,
      CAROUSEL.ITEM_MAX_WIDTH,
    ),
  );

  useEffect(() => {
    const nextWidth = calcWidth(
      windowWidth,
      CAROUSEL.PADDING,
      CAROUSEL.ITEM_MIN_WIDTH,
      CAROUSEL.ITEM_MAX_WIDTH,
    );
    setItemWidth(nextWidth);
  }, [windowWidth]);

그리고 추가적으로 resize마다 호출되는 것은 불필요하다고 생각해 특정한 간격마다만 호출될 수 있도록 throttle을 적용시켜 주었다.

완성

0개의 댓글