슬라이더를 움직임일 때 현재 슬라이더 위치를 표현하기 위해 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 };
화면의 크기의 변화에 슬라이더 크기도 맞추기 위해 반응형으로 동작하기 위해 슬라이더 너비값을 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을 적용시켜 주었다.