팀프로젝트 진행중 원래 Swiper로 보여주고 있었던 List들이, 이미지 로딩이 생각보다 오래 걸려서
skeleton ui를 사용해서 로딩중 ui를 보여주려고 했는데, swiper에서 breakpoint로 중단점을 주고 있던걸
바꾸기 귀찮아서 swiper 안에 skeleton을 사용했다.
그랬더니 로딩될 때 Skeleton이 그냥 나오는게 아니고 아래 이미지처럼 애니메이션이 생겼다..

코드는 다음과 같음.
export default function SwiperChonList({ accommodations, isLoading }) {
const skeletonArray = Array(4).fill(null);
if (isLoading) {
return (
<Swiper
slidesPerView={4}
spaceBetween={30}
loop={false}
navigation={true}
modules={[Pagination, Navigation]}
className={Styles.mySwiper}
breakpoints={{
1200: {
slidesPerView: 4,
spaceBetween: 30,
},
1000: {
slidesPerView: 4,
spaceBetween: 20,
},
868: {
slidesPerView: 3,
spaceBetween: 40,
},
710: {
slidesPerView: 3,
spaceBetween: 20,
},
630: {
slidesPerView: 2,
spaceBetween: 40,
},
530: {
slidesPerView: 2,
spaceBetween: 30,
},
400: {
slidesPerView: 2,
spaceBetween: 10,
},
180: {
slidesPerView: 1,
spaceBetween: 70,
},
}}
>
{skeletonArray.map((_, index) => (
<SwiperSlide key={`skeleton-${index}`}>
<CardSkeleton />
</SwiperSlide>
))}
</Swiper>
);
}
return (
<>
<Swiper
slidesPerView={4}
spaceBetween={30}
loop={false}
navigation={true}
modules={[Pagination, Navigation]}
className={Styles.mySwiper}
breakpoints={{
1200: {
slidesPerView: 4,
spaceBetween: 30,
},
1000: {
slidesPerView: 4,
spaceBetween: 20,
},
868: {
slidesPerView: 3,
spaceBetween: 40,
},
710: {
slidesPerView: 3,
spaceBetween: 20,
},
630: {
slidesPerView: 2,
spaceBetween: 40,
},
530: {
slidesPerView: 2,
spaceBetween: 30,
},
400: {
slidesPerView: 2,
spaceBetween: 10,
},
180: {
slidesPerView: 1,
spaceBetween: 70,
},
}}
>
{accommodations?.map((accommodation) => (
<SwiperSlide key={accommodation._id}>
<ChonCard accommodations={accommodation} />
</SwiperSlide>
))}
</Swiper>
</>
);
}
Swiper 쓰던걸 그대로 복사붙여넣기하고, ChonCard컴포넌트를 Skeleton으로만 수정했었다.
(Swiper를 custom해서 따로 컴포넌트로 만들어놓고 사용해야 하는데.. 리팩토링을 해야 겠다.)
처음에는 Skeleton에 저 애니메이션 관련된 props가 있거나 css가 있는 줄 알았는데,
아무리 찾아봐도 없어서 보니 swiper에서 width가 계속 바뀌고 있는걸 알 수 있었다.
해결 방법
아주 간단하게..
Swiper 안에 Skeleton을 안쓰면 끝이다.
중단점 설정해주기가 귀찮아서 그렇게 했었으나
애초에 불필요한 swiper 사용이였고 결론적으로 오류도 생겼으니 잘못된 코드였다고 본다.
const [skeletonCount, setSkeletonCount] = useState(4);
useEffect(() => {
const handleResize = () => {
const width = window.innerWidth;
if (width > 1000) {
setSkeletonCount(4);
} else if (width > 710) {
setSkeletonCount(3);
} else if (width > 400) {
setSkeletonCount(2);
} else {
setSkeletonCount(1);
}
};
// 초기 실행
handleResize();
// resize 이벤트 리스너 등록
window.addEventListener("resize", handleResize);
// cleanup
return () => window.removeEventListener("resize", handleResize);
}, []);
const skeletonArray = Array(skeletonCount).fill(null);
if (isLoading) {
return (
<div className={Styles.skeletonContainer}>
{skeletonArray.map((_, index) => (
<div key={`skeleton-${index}`} className={Styles.skeletonItem}>
<CardSkeleton />
</div>
))}
</div>
);
}
useEffect를 사용한 이유는 사용자가 페이지 width를 줄일 때마다
skeletoncount를 재설정해야하기 때문임.