이번 시간에는 팀원분이 구현해주신 버튼에 대한 코드 복기를 해보고자 한다.
하나의 Button 컴포넌트에서 다양한 size와 background-color를 적용하기 위해서는 props로 값을 받아서 동적으로 처리해야한다.
1. 따라서 먼저 Props에 대한 타입을 지정한다.
type ButtonProps = {
children: React.ReactNode;
onClick?: () => void;
type?: 'button' | 'submit' | 'reset';
variant?:
| 'primary'
| 'secondary'
| 'danger'
| 'success'
| 'tertiary'
| 'outline'
| 'kakao'
| 'google';
size?: 'small' | 'medium' | 'large';
disabled?: boolean;
className?: string;
};
type, variant, size는 리터럴 타입으로 입력받아 정해놓은 값만 입력받도록 하였다.
2. 해당 props을 type으로 입력받는다
const Button = ({
children,
onClick,
type = 'button',
variant = 'secondary',
size = 'medium',
disabled = false,
className = '',
}: ButtonProps) => {
이때 type = 'button'과 같이 기본값을 설정할 수 있다.
3. 각 스타일에 맞는 디자인 토큰을 정의한다.
const baseStyles = 'rounded-md transition-all duration-300';
const variantStyles = {
primary: 'bg-primary text-light hover:bg-hover-primary',
secondary:
'bg-secondary text-light hover:bg-hover-secondary hover:text-black',
danger: 'bg-danger text-light hover:bg-hover-danger',
success: 'bg-success text-light hover:bg-hover-success',
tertiary: 'bg-tertiary text-black hover:bg-hover-tertiary',
outline:
'border border-primary text-black hover:bg-primary hover:text-light',
kakao: 'bg-[#FEE500] text-black hover:bg-[#FFEB3B]',
google: 'bg-transparent border border-gray-300 text-gray hover:bg-gray-100',
};
const sizeStyles = {
small: 'px-4 py-1 text-xs',
medium: 'px-6 py-1.5 text-sm',
large: 'px-8 py-1.5 text-base',
};
4. 이러한 디자인 토큰들을 cn 함수를 이용하여 하나로 묶는다
const combinedStyles = cn(
baseStyles,
variantStyles[variant],
sizeStyles[size],
className,
);
4-1 여기서 cn 함수란?
import { twMerge } from 'tailwind-merge';
import { ClassValue, clsx } from 'clsx';
const cn = (...inputs: ClassValue[]): string => {
return twMerge(clsx(...inputs));
};
export { cn };
tailwind-merge와 clsx를 사용하여 Tailwind CSS 클래스 이름을 결합하는 기능이다
4-2 Button 컴포넌트에 대한 return 작성
return (
<button
type={type}
onClick={onClick}
disabled={disabled}
className={cn(
combinedStyles,
disabled && 'cursor-not-allowed opacity-60',
)}
>
{children}
</button>
);
여기서 disabled && 와 같이 조건 연산을 적용할 때에도 cn함수를 사용할 수 있다.
5. .ts 파일의 이름으로 다음과 같이 버튼 목록을 생성한다
const bookmarkCategories = ['전체', '북마크만 보기', '카테고리'];
export { bookmarkCategories };
6. 그다음 이 값을 저장할 State값을 선언하고
const [selectedCategory, setSelectedCategory] = useState('전체');
7. 그 컴포넌트에서 값을 내려준다
<BookmarkCategory
selectedCategory={selectedCategory}
onCategoryChange={setSelectedCategory}
/>
8. 버튼 목록의 컴포넌트를 구성한다
const BookmarkCategory = ({
selectedCategory,
onCategoryChange,
}: VideoCategoryProps) => {
return (
<ul className="flex flex-wrap gap-2">
{bookmarkCategories.map((category, index) => (
<li key={index}>
<Button
variant={selectedCategory === category ? 'primary' : 'outline'}
size="small"
onClick={() => onCategoryChange(category)}
>
{category}
</Button>
</li>
))}
</ul>
);
};
'패스트캠퍼스 데브캠프' 카테고리의 다른 글
토이 3 프로젝트 작성한 코드 복기 (4) - 디자인 토큰 정의 (0) | 2025.01.19 |
---|---|
토이 3 프로젝트 - 작성한 코드 복기 (3)- Router 설정 (0) | 2025.01.19 |
토이3 프로젝트 - 작성한 코드 복기 (1) - 프로젝트 정리 (0) | 2025.01.17 |
김민태의 데브캠프 2기 - 실시간 강의(면접 관련) (0) | 2025.01.14 |
토이 프로젝트 3 - zod와 react-hook-form 사용하여 유효성 검사 (0) | 2025.01.12 |