Skip to content

React Components

@teamsparta/react에서 제공하는 선언적 유틸리티 컴포넌트 모음입니다.


When

조건부 렌더링을 선언적으로 처리하는 컴포넌트입니다.

API

typescript
type Condition = boolean | (() => boolean);

interface WhenProps {
  condition: Condition;
  fallback?: ReactNode;
  children: ReactNode;
}

function When(props: PropsWithChildren<WhenProps>): ReactElement;

사용 예시

tsx
<When condition={isLoggedIn} fallback={<LoginButton />}>
  <Dashboard />
</When>

// 함수 형태의 조건도 가능
<When condition={() => items.length > 0}>
  <ItemList items={items} />
</When>

SwitchCase

값에 따른 분기 렌더링을 선언적으로 처리하는 컴포넌트입니다.

API

typescript
type CaseKey<Value> =
  | (Value extends boolean ? 'true' | 'false' : never)
  | (Value extends PropertyKey ? Value : never);

interface SwitchCaseProps<Value> {
  value: Value | null | undefined;
  cases: Partial<Record<CaseKey<Value>, ReactNode>>;
  defaultComponent?: ReactNode;
}

function SwitchCase<Value>(props: SwitchCaseProps<Value>): ReactElement;

사용 예시

tsx
<SwitchCase
  value={status}
  cases={{
    loading: <Spinner />,
    success: <SuccessMessage />,
    error: <ErrorMessage />,
  }}
  defaultComponent={<Placeholder />}
/>

// boolean 값도 지원
<SwitchCase
  value={isActive}
  cases={{
    true: <ActiveBadge />,
    false: <InactiveBadge />,
  }}
/>

Separated

자식 요소 사이에 구분자를 삽입하는 컴포넌트입니다.

API

typescript
interface SeparatedProps {
  with: ReactNode;    // 구분자 요소
  first?: boolean;    // 첫 번째 요소 앞에도 구분자 삽입 (기본값: false)
  last?: boolean;     // 마지막 요소 뒤에도 구분자 삽입 (기본값: false)
  children: ReactNode;
}

function Separated(props: PropsWithChildren<SeparatedProps>): ReactElement;

사용 예시

tsx
<Separated with={<hr />}>
  <Section1 />
  <Section2 />
  <Section3 />
</Separated>

// 결과: Section1 <hr/> Section2 <hr/> Section3

<Separated with={<Divider />} first last>
  {items.map(item => <Item key={item.id} {...item} />)}
</Separated>

Spacer

요소 사이에 공간을 추가하는 폴리모픽 컴포넌트입니다.

API

typescript
interface SpacerProps<T extends ElementType = 'div'> {
  as?: T;                                // 기본값: 'div'
  orientation?: 'vertical' | 'horizontal'; // 기본값: 'vertical'
  size?: string | number;                 // 기본값: '1rem', 숫자는 px로 변환
  style?: CSSProperties;
  // + T의 모든 props
}

const Spacer: <T extends ElementType = 'div'>(props: SpacerProps<T>) => ReactNode;

사용 예시

tsx
<div>
  <Header />
  <Spacer size={24} />
  <Content />
  <Spacer size="2rem" />
  <Footer />
</div>

// 수평 간격
<div style={{ display: 'flex' }}>
  <LeftPanel />
  <Spacer orientation="horizontal" size={16} />
  <RightPanel />
</div>

Delay

지정된 시간 후에 컨텐츠를 렌더링하는 컴포넌트입니다. Suspense fallback의 깜빡임 방지에 유용합니다.

API

typescript
// DelayProps는 패키지에서 export됨
export type DelayProps =
  | {
      ms?: number;           // 기본값: 0
      fallback?: never;
      children: (props: { isDelayed: boolean }) => ReactNode;
    }
  | {
      ms?: number;
      fallback?: ReactNode;  // 지연 중 보여줄 컨텐츠
      children?: ReactNode;  // 지연 후 보여줄 컨텐츠
    };

function Delay(props: DelayProps): ReactElement;

사용 예시

tsx
// 기본 사용: 300ms 후에 스피너 표시
<Suspense fallback={<Delay ms={300} fallback={null}><Spinner /></Delay>}>
  <AsyncComponent />
</Suspense>

// render prop 패턴
<Delay ms={500}>
  {({ isDelayed }) => isDelayed ? <Content /> : <Skeleton />}
</Delay>

InView

Intersection Observer를 래핑한 컴포넌트로, 자식 요소의 가시성을 관찰합니다.

API

typescript
interface InViewProps extends UseIntersectionObserverProps {
  children?: ReactElement | ReactElement[];
}

function InView(props: InViewProps): ReactElement | null;

사용 예시

tsx
<InView
  onEnter={() => trackImpression('banner')}
  onLeave={() => console.log('배너가 화면에서 사라짐')}
  threshold={0.5}
>
  <div>배너 영역</div>
</InView>

// 한 번만 감지
<InView onEnter={() => loadMore()} unobserveOnLeave>
  <div>무한 스크롤 트리거</div>
</InView>

Suspense

클라이언트 전용 모드를 지원하는 Suspense 래퍼 컴포넌트입니다.

API

typescript
interface SuspenseProps extends React.SuspenseProps {
  clientOnly?: boolean;  // true이면 서버에서는 fallback만 렌더링
}

function Suspense(props: SuspenseProps): ReactElement;

사용 예시

tsx
// 기본 사용
<Suspense fallback={<Spinner />}>
  <AsyncComponent />
</Suspense>

// 클라이언트 전용 (SSR에서 fallback 표시)
<Suspense clientOnly fallback={<Skeleton />}>
  <BrowserOnlyComponent />
</Suspense>

Portal

React createPortal을 편리하게 사용할 수 있는 컴포넌트입니다.

API

typescript
// PortalProps는 패키지에서 export됨
export interface PortalProps {
  children: ReactNode;
  container?: Element | DocumentFragment | null; // 기본값: document.body
}

function Portal(props: PortalProps): ReactElement | null;

사용 예시

tsx
// document.body에 렌더링
<Portal>
  <div className="modal">모달 내용</div>
</Portal>

// 특정 컨테이너에 렌더링
<Portal container={document.getElementById('modal-root')}>
  <Tooltip>도움말</Tooltip>
</Portal>