본 프로젝트 (삐삐:Best Interior)는 인테리어 정보 교환을 위한 커뮤니티로, 고화질의 사진 리소스를 사용하는 작업이 많았고, 서버에서 고용량의 사진 데이터를 받아오는 과정에서 발생 할 수 있는 사용자 불편함을 고려해야 하는 상황이었습니다.
또한, 고화질의 사진 리소스들은 불러오는데 많은 네트워크 비용이 들고, 장애 발생 가능성 또한 고려해야만 했습니다.
이러한 상황을 고려하여, 2가치 최적화 방안을 도입하였습니다.
🔨 최적화 방안 - (1). Pagenation 구현
고용량의 사진 데이터를 받아오면서 발생할 긴 로딩을 방지하기 위해, Pagenation을 구현하였음
각 페이지(쇼룸, 팁)에 12개의 개시글 단위로 Pagenation을 구현하였으며, 이를 통해 리소스가 큰 요청들을 분할하여 네트워크 트래픽을 최적화 하였음
즉, 한번에 모든 데이터를 불러오는게 아니라 12개단위로 끊어서 GET요청을 보냈음
이와 더불어 무한스크롤 기능을 구현하여 동적으로 추가 컨텐츠들을 로드함으로써 서버 부하와 초기 로딩시간을 줄였으며, 페이지 이탈율을 줄여 사용자 경험을 향상시키고자 하였음
// 새로운 페이지 데이터를 불러오는 함수
const loadMoreData = async (url) => {
try {
toast.loading("로딩중..."); // 데이터 로딩 중 토스트 메시지 표시
const res = await api({ ...configParams, url });
if (res.data.isLast === false) {
setShowroomData((prevData) => [...prevData, ...res.data.data]);
} else {
setShowroomData((prevData) => [...prevData, ...res.data.data]);
// 마지막 페이지 설정
setIsLastPage(res.data.isLast);
}
toast.dismiss(); // 로딩 메시지 닫기
} catch (error) {
console.error("Error loading more data:", error);
toast.error("데이터를 불러오는 중에 오류가 발생했습니다."); // 에러 시 토스트 메시지 표시
toast.dismiss(); // 에러 메시지 닫기
}
};
// IntersectionObserver를 사용하여 스크롤 감지
useEffect(() => {
// IntersectionObserver를 생성하고 등록
if (!isLastPage && !loading && isFirstPageRendered.current == true) {
// isLast가 false일 때만 IntersectionObserver 등록
const newObserver = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting && !loading) {
page.current += 1; // 페이지 번호 증가
const updatedUrl = `/feed/${feedCode}/${inputValue}${filterCode}?page=${page.current}`;
loadMoreData(updatedUrl); // 새로운 페이지 데이터를 불러오는 함수 호출
}
},
{
threshold: 0.1, // 스크롤이 target에 도달하면 새로운 데이터를 요청하는 함수 실행
}
);
// 현재 컴포넌트의 target 요소를 설정
if (target.current) {
newObserver.observe(target.current);
}
// 컴포넌트가 언마운트될 때 Observer를 해제
return () => {
if (target.current) {
newObserver.unobserve(target.current);
}
};
}
}, [filterCode, loading, searchKeyworld, isLastPage]);
또한, 응답 데이터로 다음페이지 존재여부라는 isLast 필드값을 받아서, isLast가 true일때는 더이상 추가 api 요청을 안하도록 최적화 하였음.
📸 (1) 구현 결과
무한스크롤 구현 화면
🔨 최적화 방안 - (2). 정적리소스 서버 구현
유저들의 프로필 사진이나, 작성한 게시글의 cover 사진 및 본문의 사진과 같은 정적리소스들의 네트워크 장애 발생 가능성을 고려하여 API 서버와 따로 분리, 정적리소스를 위한 서버(EC2)를 별도로 구축하였음.
예를들어, 유저가 글작성 과정에서 커버이미지 사진을 업로드시, 커버이미지를 별도의 정적리소스 서버로 업로드하기 위한 요청을 보내고, 해당 요청이 정상적으로 수행되면,
API서버는 정적리소스 서버에 업로드한 커버이미지 파일의 URL을 반환하고,
글작성을 완료하면 커버이미지 값으로 정적리소스 서버의 이미지 URL값을 저장하는 방법으로 구현하였음.