안녕하세요. 저는 현재 회사에 이직을 23년도 8월 21일에 하여 수습기간에 맨 처음 개발을 진행한 슬라이드 요소가 많더라도 dom에는 3가지의 요소만 렌더링되어 성능 최적화 된 swiper 기능을 개발을 하게 되었습니다.
만약 slides =[1,2,3]이라고 가정을 하였을때
1번이 현재 센터 슬라이드,
왼쪽으로 스와이퍼 진행 시 3번 슬라이드,
오른쪽으로 스와이퍼시 2번 슬라이드
아래 그림과 같이 개발을 진행을 해야 했어요
#개발 방향성(1)
저는 지금까지 swiper라이브러리를 사용하면서 주어진 기능만 사용을 해봤어요
loop모드 또는 slidesPerView와 같은 기능들이죠
하지만 loop모드로는 해결 할 수 없는 문제가 있었습니다.
왜냐하면 슬라이드가 3개만 있다면 3개만 dom으로 그려지고 3개의 슬라이드가 무한루프를 돌면서 잘 화면에 뿌려질테니까요
4개 이상이 된다면 dom에는 4개가 존재 할 것이고 그렇게 되면 요구사항에 맞지 않게 됩니다.
loop모드를 사용하지 않고 slides상태를 관리하면서 슬라이드가 끝날때 마다
swiper 인덱스를 0,1,2 중 1로 바꿔주면 될 것이라고 생각하여 그렇게 방향성을 정해 개발을 진행 하였습니다
#개발 방향성(2)
개발을 진행하다보니 useState로 관리하는 상태를 최대한 줄여보자라고 생각이 들었어요.
왜냐하면 최상위 컴포넌트에서 실행이 되는 컴포넌트인데 많은 useState로 관리가 되어 렌더링이 된다면 하위 컴포넌트들의 리렌더링을 피할 수 없으니까요.
before
const [swiperRef, setSwiperRef] = useState();
const [slides, setSlides] = useState([]);
const [activeIndex, setActiveIndex] = useState(0)
after
const swiperRef = useRef(null)
const [activeIndex, setActiveIndex] = useState(0)
슬라이드 배열 상태를 완전히 삭제하고 해당 컴포넌트는 activeIndex에 따라 모든 상태가 결정 되는 것 이기에 activeIndex를 제외한 모든 상태를 없애거나 useRef로 관리 하였어요
slide 렌더링 로직
// 슬라이드 무한 루프처럼 보이게하기 위한 loopIndex
// 만약 슬라이드 0에서 왼쪽으로 스와이퍼시 -1이 아닌 slide길이값을 리턴해야 하기때문
const loopIndex = useCallback(
(index: number) => {
const lastIndex = slideChildren.length - 1;
if (index < 0) return lastIndex;
if (index > lastIndex) return 0;
return index;
},
[slideChildren],
);
// 현재 바라보고 있는 activeIndex에서 -1,0,1 값을 계산하여 왼쪽 센터 오른쪽 슬라이드 렌더
const getSlideComponent = useCallback(
(indexOffset: number) => {
const element = slideChildren[loopIndex(activeIndex + indexOffset)];
return cloneElement(element.component, {
iscenter: indexOffset === 0 ? 1 : 0,
});
},
[slideChildren, activeIndex],
);
const render = useMemo(() => {
const slides = [
{ position: -1, key: 'left' },
{ position: 0, key: 'center' },
{ position: 1, key: 'right' },
];
return slides.map(({ position, key }) => (
<SwiperSlide key={`screen_${key}`} aria-hidden={position === 0 ? 'false' : 'true'}>
{getSlideComponent(position)}
</SwiperSlide>
));
}, [swiperRef, getSlideComponent, activeIndex]);
activeIndex가 바뀌면 렌더되는 부분 이에요
3가지의 이미 포지션이 정해진 배열을 새로운 배열을 만들면서 컴포넌트를 렌더링하는 방식 입니다
"loopIndex"함수로 만약 activeIndex가 받아온 슬라이드 배열보다 클 경우 다시 0으로 리턴 해줘야하는 분기처리가 되어 있어요
"getSlideComponent"은 activeIndex로 어떤 슬라이드 컴포넌트를 렌더링할지 정해주도록 개발 하였어요
activeIndex
onSlideChangeTransitionEnd={(swiper) => {
if (swiper?.touches?.diff) {
const direction = swiper.realIndex > 1 ? 1 : -1;
const slideIndex = activeIndex + direction;
handleSlideChange(slideIndex);
swiper.slideTo(1, 0, false);
}
}}
activeIndex는 터치 슬라이드가 완전히 끝날때 바꿔주도록 되어 있어요
슬라이드가 완전히 끝나면 다시 swiper.slideTo(1, 0, false);로 이용하여 swiper의 바라보고 있는 슬라이드를 1로 바꿔줍니다
#실제 프로젝트 사용모드
const slides = [
{
...slideIndex[0],
component: (
<RecommendContainer
recommendViewedCar={recommendViewedCar}
priceLowerCar={priceLowerCar}
quickMenu={quickMenu}
mainImageBanner={mainImageBanner}
daBanner={daBanner}
/>
),
},
{
...slideIndex[1],
component: (
<MeetgoContainer />
),
},
{
...slideIndex[2],
component: (
<FinanceContainer />
),
},
];
<ScreenSwiper ssrCurrentKey={ssrCurrentKey} tabComponent={<HomeTab slides={slides} />}>
{slides}
</ScreenSwiper>
실제로 2024년 04월01일 기준으로 사용된 모습이에요
사용방법은 굉장히 쉽습니다 Children으로 정해진 타입의 slide배열만 넘겨주면 되니까요!
https://car.encar.com/
문제해결
1. ssr처리를 안해서 seo가 안되는 문제
추가적인 기능으로 마지막으로 바라봤던 탭을 저장하고 추후에 다시 해당 사이트로 들어왔을때
저장된 탭을 보여주도록 되어 있었어요. 저장된 탭을 처음 렌더링할때 seo가 제대로 안잡히는 문제가 있었습니다
해결은 서버사이드 타이밍에 탭이 저장된 값을 파싱하여 해당 탭 index를 활용하여 어디를 바라볼건지 알 수 있게 처리 하였어요
2. 슬라이드시 깜빡이는 현상
현재는 사이트에 3개의 탭만 존재하여 굳이 컴포넌트가 다시 만들어지는 일과 깜빡이면 안되는게 당연했어요. 하지만 깜빡이고 상태값을 전부 잃어 버리는 것 같았습니다.
컴포넌트를 재사용하도록 수정하였어요
3. 슬라이드시 속도가 느림 현상
저는 ScreenSwiper라는 컴포넌트만 개발을 했고 슬라이드 요소 컴포넌트들은 다른 개발자가 참여 하였습니다. 해당 문제는 ScreenSwiper 별개로 수많은 carList를 조회하면서 각각의 car를 한번씩 api, cookie등 조회를 하는 것이 문제였어요.
해당 조회를 container컴포넌트쪽에서 한번에 조회처리 하도록 수정하였습니다
'개발' 카테고리의 다른 글
오래된 CRA -> vite 로컬 환경 마이그레이션 작업기 (0) | 2024.05.28 |
---|---|
Vite(react) production배포시 IE11호환 되지 않는 문제 (0) | 2024.05.28 |
[velog 2023-09-22] turborepo watch모드 build시 종속성 순서 보장하지 않는 문제 (0) | 2024.05.28 |
[velog 2023-06-23] 아이웨딩 스드메 계산기 개편 후기/회고 (0) | 2024.05.28 |
[velog 2023-06-08] NextJS v13 App Router의 스트리밍SSR (0) | 2024.05.28 |