skills/doyoonear/skills-and-agents/component-architecture

component-architecture

SKILL.md

Component Architecture Guide

React 컴포넌트 설계 시 활용할 수 있는 아키텍처 패턴 모음입니다. 실제 프로젝트에서 검증된 패턴들을 기반으로 작성되었습니다.

패턴 목록

패턴 설명 적용 시나리오
기본 + 확장 패턴 기본 컴포넌트를 확장하여 변형 생성 Modal → ConfirmModal, Sheet → ActionSheet
Provider + Hook 패턴 Context로 상태 관리, Hook으로 접근 전역 상태, 모달 시스템, 테마

💡 상세 가이드는 patterns/ 폴더의 개별 파일을 참조하세요.


1. 기본 + 확장 패턴

파일: patterns/base-extension.md

핵심 개념

기본 컴포넌트 (Base)
├── 최소한의 공통 기능만 포함
├── children으로 내용 확장 가능
└── 제네릭 타입으로 타입 안전성 확보

확장 컴포넌트 (Extension)
├── 기본 컴포넌트를 import하여 사용
├── 특화된 UI/로직 추가
└── 별도 폴더에 그룹화 (예: modals/, sheets/)

적용 시나리오

  • 모달 시스템: ModalConfirmModal, AlertModal, FormModal
  • 시트 시스템: SheetActionSheet, FilterSheet, ShareSheet
  • 카드 시스템: CardProductCard, UserCard, ArticleCard
  • 버튼 시스템: ButtonIconButton, LoadingButton, SocialButton

폴더 구조

components/
├── Modal.tsx           # 기본 모달
├── Sheet.tsx           # 기본 시트
├── modals/             # 모달 확장 컴포넌트들
│   ├── ConfirmModal.tsx
│   └── AlertModal.tsx
└── sheets/             # 시트 확장 컴포넌트들
    ├── ActionSheet.tsx
    └── FilterSheet.tsx

빠른 예시

// 기본 컴포넌트 - 제네릭 타입 사용
interface SheetProps<T = unknown> {
    close: (result?: T) => void
    title?: string
    children: React.ReactNode
}

export function Sheet<T = unknown>({ close, title, children }: SheetProps<T>) {
    return (
        <Backdrop onClick={() => close()} alignBottom>
            <div className="bg-white rounded-t-2xl">
                {title && <h2>{title}</h2>}
                {children}
            </div>
        </Backdrop>
    )
}

// 확장 컴포넌트 - 기본 컴포넌트 래핑
interface ActionSheetProps<T> {
    close: (result?: T | null) => void
    title?: string
    options: Array<{ label: string; value: T; destructive?: boolean }>
}

export function ActionSheet<T>({ close, title, options }: ActionSheetProps<T>) {
    return (
        <Sheet close={close} title={title}>
            {options.map((option) => (
                <button key={String(option.value)} onClick={() => close(option.value)}>
                    {option.label}
                </button>
            ))}
            <button onClick={() => close(null)}>취소</button>
        </Sheet>
    )
}

2. Provider + Hook 패턴

파일: patterns/provider-hook.md

핵심 개념

OverlayProvider (Context Provider)
├── 상태 및 로직 캡슐화
├── createPortal로 DOM 렌더링
└── 앱 최상위에서 래핑

useOverlay (Custom Hook)
├── Context 접근 유일한 방법
├── 타입 안전한 API 제공
└── 코드 추적 용이 (전역 객체 없음)

설계 원칙

원칙 설명
전역 객체 금지 overlay.open() 같은 전역 접근 금지 → 코드 추적 어려움
Hook 전용 접근 컴포넌트 내에서 useOverlay() 훅으로만 접근
명시적 의존성 Provider 없이 Hook 사용 시 명확한 에러 메시지

적용 시나리오

  • 모달/오버레이 시스템: Promise 기반 열기/닫기
  • 토스트/알림 시스템: 전역 알림 표시
  • 테마 시스템: 다크모드 토글
  • 인증 시스템: 로그인 상태 관리

빠른 예시

// Context 정의
type OverlayContextType = {
    open: <T>(render: (props: { close: (result?: T) => void }) => ReactNode) => Promise<T | undefined>
    close: (id: string) => void
    closeAll: () => void
}

const OverlayContext = createContext<OverlayContextType | null>(null)

// Provider 구현
export function OverlayProvider({ children }: { children: ReactNode }) {
    const [overlays, setOverlays] = useState<OverlayElement[]>([])

    const open = useCallback(<T,>(render: RenderFn<T>): Promise<T | undefined> => {
        return new Promise((resolve) => {
            const id = crypto.randomUUID()
            const close = (result?: T) => {
                setOverlays((prev) => prev.filter((o) => o.id !== id))
                resolve(result)
            }
            setOverlays((prev) => [...prev, { id, element: render({ close, isOpen: true }) }])
        })
    }, [])

    return (
        <OverlayContext.Provider value={{ open, close, closeAll }}>
            {children}
            {mounted && createPortal(/* overlay 렌더링 */, document.body)}
        </OverlayContext.Provider>
    )
}

// Hook 구현
export function useOverlay() {
    const context = useContext(OverlayContext)
    if (!context) {
        throw new Error('useOverlay must be used within OverlayProvider')
    }
    return context
}

패턴 선택 가이드

컴포넌트 설계 시 질문:

1. "같은 기본 구조에서 여러 변형이 필요한가?"
   → YES: 기본 + 확장 패턴 사용

2. "여러 컴포넌트에서 공유되는 상태/기능인가?"
   → YES: Provider + Hook 패턴 사용

3. "두 가지 모두 해당하는가?"
   → 조합 사용 (예: Overlay 시스템)

참고 사항

  • 각 패턴의 상세 구현은 patterns/ 폴더의 개별 파일 참조
  • 실제 적용 예시는 modal-system-generator skill 참조
  • 새 패턴 추가 시 이 문서와 patterns/ 폴더에 함께 추가
Weekly Installs
1
First Seen
12 days ago
Installed on
amp1
cline1
openclaw1
opencode1
cursor1
kimi-cli1