본문 바로가기
일상이 개발

React 공통 컴포넌트 시스템 설계 가이드 – 재사용성과 확장성을 모두 잡는 전략

by 디어노미 2025. 4. 19.
반응형

🧱 React 앱에서 공통 컴포넌트 시스템 구축 전략

React 프로젝트를 하다 보면 가장 많이 반복하는 작업이 UI 컴포넌트 만들기입니다.
버튼, 입력창, 모달, 드롭다운 등은 거의 모든 화면에 등장하죠.

이럴 때마다 새로 만드는 게 아니라, 한 번 만들어서 계속 쓰면 얼마나 좋을까요?
그게 바로 공통 컴포넌트 시스템(Common Component System)의 핵심입니다.

이번 글에서는 다음과 같은 내용을 중점적으로 다룹니다:

  • ✅ 공통 컴포넌트를 만들 때 꼭 고려할 요소
  • 📦 폴더 구조와 네이밍 규칙
  • 🔁 재사용성과 확장성을 고려한 설계
  • 🧪 테스트 및 문서화 전략
  • 🎨 디자인 시스템과의 연동

🎯 왜 공통 컴포넌트가 중요한가?

UI를 매번 새로 만드는 대신 한 번 만들고 여러 곳에서 재사용하면 다음과 같은 효과를 얻을 수 있습니다.

  • ⏱ 생산성 향상: 코드 재사용으로 개발 속도 증가
  • 🎨 UI 일관성: 화면마다 디자인이 다르다는 불만 해소
  • 🛠 유지보수 용이: 수정 시 한 곳만 변경하면 전체 반영
  • 👥 협업 효율: 팀원이 언제든 예측 가능한 컴포넌트 활용 가능

즉, 공통 컴포넌트 시스템은 단순한 UI 재사용이 아니라 프론트엔드 아키텍처의 핵심입니다.


📦 1. 폴더 구조와 네이밍 전략

컴포넌트를 체계적으로 관리하려면 폴더 구조부터 신경 써야 합니다.

/src
 └── components
     ├── Button
     │   ├── Button.tsx
     │   ├── Button.test.tsx
     │   └── index.ts
     ├── Input
     ├── Modal
     └── index.ts

추천하는 네이밍 전략:

  • 폴더명 = 컴포넌트명
  • 컴포넌트는 단일 책임 원칙(SRP)을 따름
  • index.ts로 barrel export 구성
// components/index.ts
export { default as Button } from './Button';
export { default as Input } from './Input';

→ 이렇게 하면 import { Button } from '@/components' 형태로 깔끔하게 사용할 수 있습니다.


🧩 2. 버튼 컴포넌트를 예로 보는 설계 전략

✅ 목표: 다양한 상태와 용도를 포괄하면서도 사용법은 간단하게

{`interface ButtonProps {
  variant?: 'primary' | 'secondary' | 'danger';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  onClick?: () => void;
  children: React.ReactNode;
}`}
{`const Button = ({ variant = 'primary', size = 'md', disabled, ...props }: ButtonProps) => {
  return (
    <button
      className={\`btn \${variant} \${size}\`}
      disabled={disabled}
      {...props}
    >
      {props.children}
    </button>
  );
};`}

이런 식으로 옵션을 조합하면, 하나의 버튼 컴포넌트로 다양한 스타일과 기능을 포괄할 수 있습니다.

{`기본
삭제`}

🛠 3. 확장성과 재사용성을 고려한 패턴

공통 컴포넌트는 하나로 끝나는 게 아니라 유지보수와 확장이 쉬워야 합니다.

전략 1: 공통 Props 인터페이스 정의

{`// types.ts
export interface CommonProps {
  className?: string;
  style?: React.CSSProperties;
}`}

→ 각 컴포넌트에서 extends 하면 일관성 유지에 도움이 됩니다.

전략 2: Slot 기반 확장

{`

→ 특정 영역만 사용자 정의(Slot)하고, 나머지는 재사용 구조로 가져갑니다.


🧪 4. 공통 컴포넌트 테스트 전략

공통 컴포넌트는 많은 곳에서 사용되므로 깨지지 않도록 테스트 자동화가 중요합니다.

{`// Button.test.tsx
import { render, screen } from '@testing-library/react';
import Button from './Button';

test('버튼이 children 텍스트를 렌더링한다', () => {
  render(확인);
  expect(screen.getByText('확인')).toBeInTheDocument();
});`}

또한 Storybook과 함께 사용하면 디자이너-개발자 협업에도 큰 도움이 됩니다.

{`// Button.stories.tsx
export const Primary = () => <Button variant="primary">확인</Button>;`}

🎨 5. 디자인 시스템과 연동 전략

컴포넌트 시스템은 종종 디자인 시스템(Design Token)과 연결됩니다.

예시: tailwind.config.js or theme.ts

{`export const theme = {
  colors: {
    primary: '#1E90FF',
    danger: '#FF4D4F'
  },
  spacing: {
    sm: '8px',
    md: '16px',
    lg: '24px'
  }
};`}

→ 컴포넌트 내부에서 해당 토큰을 사용하면 디자인 일관성이 확보됩니다.

{`const Button = styled.button\`
  padding: \${theme.spacing.md};
  background-color: \${theme.colors.primary};
\`;`}

🔄 6. 실전에서 흔히 쓰이는 공통 컴포넌트 목록

컴포넌트 역할
Button 클릭 인터랙션, CTA
Input 입력창, 유효성 표시
Modal 중첩 레이어, 경고/상세
Toast 짧은 알림 메시지
Tooltip 정보 도움말
FormLabel / FormField 입력 요소 묶음

✅ 마무리 요약

전략 항목 핵심 요약
폴더 구조 컴포넌트별 폴더 + index.ts 정리
Props 설계 variant, size 등 확장 가능한 구조
재사용성 확보 공통 인터페이스, Slot, 스타일 분리
테스트 Jest + React Testing Library + Storybook
디자인 시스템 연계 Tailwind, Theme 기반 Token 적용

공통 컴포넌트 시스템은 단순한 재사용을 넘어 코드 품질, 협업 효율, 디자인 일관성까지 모두 책임지는 구조입니다.
지금부터라도 체계적으로 구축해보세요. 프로젝트가 훨씬 건강해집니다! 🚀

반응형