회사에서 Vue로 작성된 레거시 코드를 React로 마이그레이션 작업을 하면서, 슬라이더 컴포넌트를 만들어야 하는 상황이 생겼습니다.
기존 레거시 코드는 vue-slider를 사용하고 있었는데, React 환경에 맞는 라이브러리를 변경해야하는 상황이었습니다. 따라서 react-slick을 도입했고, 기존의 기능과 디자인을 재현하기 위해 노력했던 흔적을 정리합니다.
블록 넘버 배열의 각 넘버를 슬라이더의 요소에 하나씩 표시하고, 슬라이더에서 메인이 되는 요소의 인덱스를 상태를 통해서 관리합니다.
메인이 되는 요소에는 투명도와 크기를 변경해주어 메인이 되는 요소임을 표시해줍니다.
React-slick 라이브러리 자체에는 JQuery에 대한 의존성이 없습니다. 다만 slick의 내장 css에는 JQuery에 대한 의존성이 있었습니다.
//⛔️jQuery 의존성 존재
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
이번 프로젝트에서 JQuery에 대한 의존성 추가를 지양했기 때문에, 아래 링크에서 css 파일을 따로 가져온 후, style 디렉토리에 넣어주었습니다. 그리고 코드의 font 등 파일을 가져오는 코드는 주석처리하였습니다.
https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.9.0/slick-theme.css
https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.9.0/slick.css
그리고 슬라이더 컴포넌트에서 해당 css 파일을 import 해주었습니다.
import '../styles/slick-theme.scss';
import '../styles/slick.scss';
blockList에 담긴 각각의 번호를 슬라이더에 표시해줍니다. 이때 슬라이더에서 가장 왼쪽에 표시되는 블록의 index를 currentIndex라는 상태로 관리해줍니다.
const [currentIndex, setCurrentIndex] = useState(0);
const blockList = [1, 2, 3, 4, 5];
가장 왼쪽에 표시되는 블록에는 'active' 클래스를 부여해서 css 속성을 적용해줍니다.
${currentIndex === index && styles.active}
react slick을 사용하는 경우에는 setting을 정의해주어 Slider의 props로 전달해줍니다.
공식 홈페이지에 나와있는 기본 형태는 다음과 같습니다.
import React, { Component } from "react";
import Slider from "react-slick";
export default function SimpleSlider(){
const settings = {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1
};
return (
<div>
<h2> Single Item</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
);
}
저는 셋팅을 요구사항에 맞게 다음과 같이 변경하였습니다.
const defaultSetting = {
dots: true,
infinite: true,
speed: 500,
};
export default function BlockSlider() {
const [currentIndex, setCurrentIndex] = useState(0);
const blockList = [1, 2, 3, 4, 5];
const settings = {
...defaultSetting,
slidesToShow: 3,
slidesToScroll: 1,
beforeChange: (_, newIndex) => {
setCurrentIndex(newIndex);
},
};
}
setting의 마지막 속성인 beforeChange는 슬라이더의 인덱스가 변경되기 직전에 호출되는 콜백함수입니다.
이 콜백함수의 첫번째 인자는 oldIndex(변경되기 이전의 인덱스) 두번째 인자는 newIndex(변경된 이후의 인덱스) 입니다.
이전 인덱스 정보는 사용할 필요가 없어서 첫번째 인자에 '_'를 주었습니다.
전체 코드를 보면 다음과 같습니다
import React, { useState } from 'react';
import Slider from 'react-slick';
import '../styles/slick-theme.scss';
import '../styles/slick.scss';
import styles from '../styles/BlockSlider.module.scss';
const defaultSetting = {
dots: true,
infinite: true,
speed: 500,
};
export default function BlockSlider() {
const [currentIndex, setCurrentIndex] = useState(0);
const blockList = [1, 2, 3, 4, 5];
const settings = {
...defaultSetting,
slidesToShow: 3,
slidesToScroll: 1,
beforeChange: (_, newIndex) => {
setCurrentIndex(newIndex);
},
};
return (
<div className={styles.container}>
<h2> Single Item</h2>
<Slider {...settings} className={styles.slider}>
{blockList.map((blockNumber, index) => (
<div key={index} className={styles.block}>
<div
className={`${styles.circle} ${
currentIndex === index && styles.active
}`}
>
<p className={styles.content}>{blockNumber}</p>
</div>
</div>
))}
</Slider>
</div>
);
}
코드에서 보면 map의 콜백함수에서 index가 현재 표시되고 있는 currentIndex와 일치할 때, active 클래스를 주어서 css를 변경합니다.
다음 코드의 결과입니다.
afterChange는 슬라이더의 인덱스가 변경된 직후에 실행되는 콜백함수입니다.
beforeChange 대신에 afterChange를 사용해서 코드를 작성해보았습니다.
const settings = {
...defaultSetting,
slidesToShow: 3,
slidesToScroll: 1,
afterChange: (newIndex) => {
setCurrentIndex(newIndex);
},
};
이렇게 작성했을 때, 다음과 같은 결과가 나타났습니다
보시다시피 슬라이드의 요소가 변경되고 난 후에야 currentIndex의 상태변경이 이루어지기 때문에, css 적용되는 데 딜레이가 발생하고 있습니다.
단순히 현재 활성화된 요소의 인덱스 정보만 알면 되는 경우에는 afterChange를 사용해도 될 것 같습니다.
하지만 활성화된 요소의 css 변경이 슬라이드가 넘어가는 애니메이션과 동시에 적용되어야 할 때에는 beforeChange가 더 적합해보입니다.
프로젝트를 하면서 불필요한 의존성은 늘리지 않으려고 하고 있습니다만, 더 깔끔한 코드와 디자인을 자랑하는 라이브러리의 유혹에 넘어가지 않기란 쉽지 않은 것 같습니다. 특히나 신입이고, 혼자서 프로젝트를 하는 입장에서 기한을 맞추기 위해 어쩔 수 없이 라이브러리를 사용하게 되는 것 같습니다. 라이브러리를 사용하기 전에 라이브러리의 공식 문서와 예제를 꼼꼼히 확인하여 더 효율적으로 사용하는 것이 중요할 것 같습니다.