모동숲 마켓에서 사용하는 여러번 사용하는 버튼 디자인은 크게 3가지가 있다.
1. 민트색 버튼 2. 흰색 버튼 3. 회색 버튼
TailwindCSS를 사용해서 만들면서 그때 그때 className을 복사해서 만들었는데, 디자인이 겹치기 때문에 버튼 컴포넌트를 만들어서 재사용하여 코드의 중복을 줄이고 디자인을 일관되게 유지하도록 하려고 한다.
컴포넌트를 사용하는 곳에서 props를 통해 색상, 사이즈, 클릭 이벤트 핸들러 등을 전달할 수 있다.
import { ReactNode } from 'react';
type Color = 'mint' | 'white' | 'gray';
type Size = 'sm' | 'md' | 'lg';
interface ButtonProps {
type?: 'submit' | undefined; // type이 undefined인 경우에는 'button'으로 지정
color: Color;
size: Size;
className?: string; // 추가로 적용하고 싶은 className이 있을 경우 사용
onClick?: () => void;
children: ReactNode; // children 속성에는 string 뿐만 아니라 <svg> 요소가 포함될 수도 있어서 ReactNode 타입을 사용했다.
}
function Button({ type, color, size, className, onClick, children }: ButtonProps) {
let combinedClassName = ''; // 이 변수에 className을 중첩시킨다.
switch (color) {
case 'mint': {
combinedClassName = 'mr-2 rounded-lg border border-mint bg-mint font-semibold text-white hover:bg-hover-mint focus:ring-ring-mint';
break;
}
case 'white': {
combinedClassName = 'mr-2 rounded-lg border border-mint bg-transparent font-semibold text-mint hover:bg-gray-100 focus:ring-gray-300';
break;
}
case 'gray': {
combinedClassName =
'inline-flex items-center rounded-lg border border-gray-300 bg-white text-center font-medium text-gray-900 hover:bg-gray-100 focus:outline-none focus:ring-gray-200';
break;
}
}
switch (size) {
case 'sm': {
combinedClassName += ' py-1.5 px-3 text-sm focus:ring-4';
break;
}
case 'md': {
combinedClassName += ' py-2 px-4 text-sm focus:ring-2';
break;
}
case 'lg': {
combinedClassName += ' py-2 px-4 text-base focus:ring-4';
break;
}
}
return (
<button type={type ? type : 'button'} className={`${combinedClassName} ${className}`} onClick={onClick}>
{children}
</button>
);
}
export default Button;
<Button onClick={onSubmit} color='mint' size='md'>
변경
</Button>
<Button onClick={toggleIsEditing} color='white' size='md'>
취소
</Button>
사실 이 방법 이전에는 index.css
파일에 @layer components
디렉티브 내부에 버튼마다 클래스를 작성했는데, 이 방법은 코드의 유지 보수성과 가독성에도 좋지 않고, CSS 파일이 더 복잡해지고 읽기 어려워지기 때문에 일반적으로 권장되지 않는다고 한다.
@layer components { /* ❌ */
button {
&.mint {
...
}
&.white {
...
}
}
}
@layer
디렉티브를 사용하면 레이어 간의 의존성이 증가할 수 있다. 예를 들어, 하나의 레이어에서 정의된 클래스가 다른 레이어에서 사용되는 경우, 코드를 이해하기 어려워질 수 있고 스타일 충돌이 발생할 수도 있다.index.css
파일은 주로 전역 스타일을 정의하는 데 사용된다. 많은 @layer
디렉티브를 사용하면 전역 스타일과 컴포넌트 스타일이 섞이게 되어 관심사 분리가 어려워질 수 있다.➡️ 따라서 컴포넌트를 단독으로 유지하고 재사용 가능하게 하려면, 컴포넌트 별로 스타일을 분리하는 것이 좋다.
그리고 index.css
파일에서 @layer
디렉티브를 사용하는 경우는 전역 스타일을 정의하거나 필요한 경우에만 컴포넌트 관련 스타일을 추가하는 방식으로 사용하는 것이 코드의 가독성과 유지보수성에 좋다.
지은님 코드 본적이 있는데 switch를 되게 잘쓰시는거 같아요 컴포넌트화 읽기도 쉽고 간편해서 잘작성하신거같네요! 굿입니다