사내 디자인 시스템 라이브러리에 포함된 Carousel 컴포넌트가 가지고 있었던 문제들을 해결하기 위해, 컴포넌트를 직접 구현한 경험을 공유합니다.
https://github.com/vgihan/react-simplify-carousel
첫 번째는 Grid 컴포넌트와의 의존입니다. GridList는 아래와 같이 각 element를 특정 비율 List로 x축 나열할 수 있는 컴포넌트인데요, 레거시 Carousel은 이 GridList를 감싸서 Carousel UI를 구현하도록 설계되었었습니다. 오른쪽 코드와 같이 Carousel 내부 styled component인 InnerRoot 에서 CarouselBody 하위에 soso-grid의 style을 선언하고 있습니다. 이는 Carousel의 children으로 반드시 Grid 컴포넌트를 사용해야한다고 강제하는 것과 같습니다. Grid가 아니면 style이 깨질 것이기 때문이죠.
<Carousel>
<Grid>
<Grid.Unit size={1/3}>{element}</Grid.Unit>
<Grid.Unit size={1/3}>{element}</Grid.Unit>
<Grid.Unit size={1/3}>{element}</Grid.Unit>
{...}
</Grid>
</Carousel>
const InnerRoot = styled.div`
& > ${CarouselBody} > .soso-grid > * {
height: 100%;
${({ active }) => (active ? 'padding: 0 !important;' : '')}
}
& > ${CarouselBody} > .soso-grid > .soso-grid-unit,
& > ${CarouselBody} > .soso-grid > * > * > .soso-grid-unit {
${({ active }) => (active ? 'max-width: 100%;' : '')}
}
`;
이렇게 Grid 컴포넌트에 강하게 의존하고 있는 모습은 크게 두 가지의 문제점을 만들어냅니다.
첫째, Carousel 컴포넌트를 사용하는 개발자로 하여금 children props를 예측하기 어렵게 만들어 생산성을 저하시킵니다.
둘째, Grid 컴포넌트의 변경에 영향을 받게 됩니다. Grid의 style을 수정하게 되면 Carousel UI에 문제가 발생하는 지 항상 염두하면서 Grid 컴포넌트를 수정해야합니다.
따라서 Grid 컴포넌트와 Carousel 컴포넌트의 의존을 끊어내어 Grid 컴포넌트가 보다 변경에 유연하도록, 그리고 Carousel의 children props가 예측하기 쉽도록 수정해야합니다.
두 번째는 외부 라이브러리 의존으로 인해 초기 렌더링 시 style이 적용되지 않는 문제입니다. 레거시 Carousel은 siema 라고 하는 바닐라 JavaScript로 작성된 Carousel UI를 구현하는 라이브러리입니다. siema는 Carousel 이라고 하는 class 로 구현이 되어있는데요, 이 class의 인스턴스가 생성되는 시점에 DOM을 수정하여 Carousel UI를 완성시킵니다. 그러다보니 React에서 사용할 때 effect 레이어에서 Carousel 인스턴스를 생성하게 됩니다. 이로 인해 아래와 같은 문제를 발생시킵니다.

Effect 실행 전

Effect 실행 후
effect를 소비하기 전 초기 렌더링 시에는 좌측 이미지와 같이 carousel의 style이 적용되지 않아 effect 소비 후와 비교했을 때 일치하지 않는 UI가 보여집니다. 이후 브라우저에서 effect를 소비했을 때 JavaScript 계산이 반영되어 오른쪽과 같이 style이 적용되게 됩니다. 이는 유저가 처음 서비스를 접속했을 때 UI의 깜빡임으로 인해 다른 element들이 위치가 바뀌는 등 유저 경험에 좋지 않은 영향을 끼칩니다.