BOOKER 프로젝트(도서 추천 서비스)에서 적용한 합성 컴포넌트 패턴을 활용한 로딩 상태별 UI 구현 경험을 공유하려고 합니다. 이 패턴을 통해 애플리케이션 전반의 로딩 상태 관리를 효율적으로 개선할 수 있었습니다.
|💡 프로젝트 주요 기술 스택: Next.js, SCSS , React Query
개발하다 보면 API 요청 중 로딩 상태를 표시해야 하는 경우가 많습니다. 특히 이를 스켈레톤으로 표시한다면 로딩 전후의 화면의 레이아웃, 스타일은 동일성을 유지해야합니다. 이로 인한 코드 관리의 비효율을 고민하게 되고 Booker 프로젝트에서도 다음과 같은 문제점들이 있었습니다.
다른 패턴(HOC, Render Props 등)과 비교하여, 다음의 이유들로 합성 컴포넌트 패턴을 선택했습니다.
여러 컴포넌트들을 조합해서 사용하는, 도서 상세 페이지를 예를 들어서 설명드리겠습니다.
자식 컴포넌트의 로딩 상태별 UI를 조합해, 부모 컴포넌트의 로딩 상태별 UI를 구현하는 방식으로 진행했습니다.
📌 BookDetails 구조
│
├── 🟢 Loaded (실제 데이터 로드 후 렌더링)
│ │
│ ├── 📖 BookCover.Loaded
│ ├── 📑 BookMeta.Loaded
│ ├── 📝 BookDescription.Loaded
│
├── ⚪ Skeleton (로딩 중 UI)
│ │
│ ├── 📖 BookCover.Skeleton
│ ├── 📑 BookMeta.Skeleton
│ ├── 📝 BookDescription.Skeleton
└──
로딩 UI(이하 Sekeleton)와 로딩 완료 후 UI(이하 Loaded)간 레이아웃과 스타일을 일관되게 유지하는 것은 중요합니다. 이를 위해서, 레이아웃 컴포넌트를 별도로 분리하여 재사용함으로써 코드 중복을 줄이고 코드 관리의 편의성을 높였습니다.
👩💻 예시 코드
// Layout 컴포넌트 정의
const Layout = ({ children, className }) => (
<section className={className ? classNames(styles.container, className) : styles.container}>
{children}
</section>
);
// 사용 예시
const BookDetailsLoaded = ({ bookDetailData }) => (
<Layout>
{/* 콘텐츠 */}
</Layout>
);
const BookDetailsSkeleton = () => (
<Layout className={styles.containerSkeleton}>
{/* 스켈레톤 UI */}
</Layout>
);
Skeleton와 Loaded의 일부분에서 스타일 차이가 있는 경우가 있습니다. 이럴 때에는 위의 코드처럼 레이아웃 컴포넌트에 다른 스타일을 적용한 클래스를 받을 수 있도록 해주었습니다.
만약 CSS-in-JS라면, 스타일 확장을 활용할 수 있습니다.
👩💻 스타일 확장을 활용한 CSS-in-JS 예시 코드
// 기본 컨테이너 스타일 정의
const Container = styled.section`
// 공통 스타일 정의
`;
// 스켈레톤 컨테이너 스타일 확장
const SkeletonContainer = styled(Container)`
//추가 스타일 정의
`;
// Layout 컴포넌트 정의
const Layout = ({ children, isLoading }) => {
return isLoading ? (
<SkeletonContainer>{children}</SkeletonContainer>
) : (
<Container>{children}</Container>
);
};
합성 컴포넌트 패턴으로 로딩 상태별 UI를 구현했을 때 얻은 가장 큰 이점은 DX였습니다.
하나의 파일에서 컴포넌트의 로딩 상태별 UI를 관리할 수 있어서, UI를 일관되게 관리할 수 있었습니다. 또한 스토리북과 함께 활용하기 좋았습니다.
자식 요소의 로딩 상태별 UI를 조합해 부모 요소의 로딩 상태별 UI를 구성하는 방식은 개발 속도를 높일 수 있었고 코드 중복을 줄일 수 있었습니다.
개발자의 개발 편의성이 향상되니, 일관적인 UI 제공이 보다 원활해지고 그로 인해 사용자 경험에도 긍정적인 영향을 미치지 않았을까하는 생각이 듭니다.
우아한테크코스에서 여러 프론트엔드 미션을 진행하면서도, 로딩 상태별 UI 관리를 효율적으로 하는 것은 늘 고민이었습니다. 리뷰어분들에게 조언을 구했지만 시간상 이야기해주신 방법으로 작업을 진행하지 못했습니다. 이번 작업은 늘 머릿속에 있던 작업을 실제로 구현해 볼 수 있어서, 재미있었습니다.
또한 개발을 처음 시작할때에는 "스켈레톤은 구현했다!"라는 것에 즐거웠다면 이제는 어떻게 코드를 효율적으로 쉽게 관리를 할 것인가에 대한 해답을 제시하는 것이 더 큰 즐거움이자 개발자로서의 하나의 목표가 된 것 같습니다.
앞으로도 이런 고민들을 통해 얻은 인사이트를 공유할 수 있었도록, 부단히 성장해보겠습니다.😆
글 읽어주셔서 감사합니다! 🙌