2차 프로젝트에서는 라이브러리를 활용할 수 있어서 무한스크롤을 구현할때 Infinite-scroll-component를 사용해보았다. 리액트 라이브러리를 사용하면 더 수월하게 기능구현이 가능할 줄 알았는데 오히려 신경쓸 것도 많고 처음에 조금 헤맸던 기억이다.
이번에 최적화에 대해 공부하면서 2차 프로젝트 무한스크롤 부분을 디바운스를 사용해서 리팩토링 해보았다.
우선 Infinite-scroll-component 라이브러리 기본 사용예제이다.
<InfiniteScroll
dataLength={this.state.items.length}
next={this.fetchMoreData}
hasMore={true} // 추가 데이터를 가져올지 여부를 판단
loader={<h4>Loading...</h4>}
>
{this.state.items.map((_, index) => (
<div style={style} key={index}>
div - #{index}
</div>
))}
</InfiniteScroll>
아래는 나의 코드이다.
<InfiniteScroll
dataLength={product?.length}
next={() => fetchProducts(product?.length)}
hasMore={hasMore}
loader={<LoadingText>Loading...</LoadingText>}
endMessage={
<BackgroundBox>
<LoadingMotion />
</BackgroundBox>
}
style={{ overflow: 'visible', scrollBehavior: 'smooth' }}
>
<ImageContainers>
{product?.map(content => (
<FirstImage key={content.id}>
<Image
src={content.thumbnail}
onClick={() => navigate(`/productdetail/${content.id}`)}
/>
<TextContainer>
<CampName>{content.campsite_name}</CampName>
<CampRegion>{content.region_name}</CampRegion>
<CampPrice>
{Math.floor(Number(content.price)).toLocaleString()} 원
</CampPrice>
</TextContainer>
</FirstImage>
))}
</ImageContainers>
</InfiniteScroll>
);
};
무한 스크롤을 구현하는 동안 불필요한 데이터 요청 등이 발생할 수 있는데 Infinite Scroll 라이브러리에서 제공하는 scrollThreshold prop 등을 활용하여 최적화 시킬 수 있다.
최적화의 방법에는 여러가지가 있는데, 디바운스, 데이터 캐싱, 레이지 로딩, limit 값을 사용하여 상품 데이터 양을 조절 할 수도 있다.
디바운스(Debounce)는 주어진 시간 동안 연속적으로 발생하는 이벤트를 하나로 묶어주는 기술이다. 특히, 스크롤을 할 때 마다 렌더링이 일어날 때나, 사용자의 입력과 같은 연속적인 이벤트를 처리할때 유용하다.
디바운스를 적용하면, 사용자가 스크롤을 이동할때 일정 시간 동안 연속적으로 발생하더라도 마지막 이벤트가 발생한 후 일정 시간이 경과할 때까지 기다린 후에 요청을 보낸다. 이렇게 함으로써 이벤트가 연속적으로 발생할 경우에도 불필요한 요청을 방지하고 성능을 최적화할 수 있게 해준다.
나는 처음에 offset, limit 값을 지정하여 무한스크롤을 구현하였는데,
이후에 추가로 스크롤 이벤트를 디바운스 처리하여 최적화를 시켜보았다.
...
// 이전 코드 생략
const debouncedFetch = () => {
clearTimeout(timerId);
timerId = setTimeout(() => {
fetchProducts(product.length);
}, 500); // 500ms 디바운스 설정
};
// 스크롤 이벤트를 디바운스 처리하여 최적화
const handleScroll = () => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
debouncedFetch();
}
};
...
return (
<InfiniteScroll
dataLength={product?.length}
next={() => fetchProducts(product?.length)}
hasMore={hasMore}
loader={<LoadingText />}
endMessage={
<BackgroundBox>
<LoadingMotion />
</BackgroundBox>
}
style={{ overflow: 'visible', scrollBehavior: 'smooth' }}
>
최적화에대한 고민을 요즘 많이 하게 되는데, 여러가지 방법들을 적용해보고 하나하나 테스트 해보는게 중요한 것 같다. 많은 최적화 방법들이 있지만 무조건 이 방법으로 해야해 이게 아니라 상황에 맞게 적절하게 골라 사용하는법을 더 공부해야겠다고 느꼈다.