과거(이글을 쓰기 10분 전)의 무지한 저는 말이죠..
하나의 제대로 된 컴포넌트를 만능으로 만들어서 재사용할 수 있다고 믿었고, 그렇게 하고 싶었습니다. 그리고 공통 컴포넌트는 재사용을 위한 것이다 라고만 생각했구요.. 하핳
그럼 어떻게 되냐.. props로 디테일한 걸 다 받아야 해요.
다행인지 아닌지 최근 프로젝트에서는 2-3개정도만 추가해서 끝났지만, 만약 회사 같이 어떤 요구사항이 어떤식으로 추가될지 모르는 상황 속에선 전 무능력한 자입니다.

(단일 책임 원칙)> 확장 규칙 설계 > 네이티브 요소의 활용 > 웹 접근성
여기서 요점은 공통 컴포넌트가 단지 재사용을 하기 위한 컴포넌트가 아니라 위의 3가지를 활용하여 완성도 있는 컴포넌트를 만들어야 한다는 것이다.
아래의 링크를 통해 단일 책임 원칙 글을 미리 보고 오면 좋을 것 같다.
내가 공통 컴포넌트를 정하는 기준은 "두 군데 이상에서 반복" 이였다.
[반복] 된다는 이 기준은 명확한 것인가?
디자인과 안의 구성 패턴이 같으면 반복되는 것이라고 볼 수 있는가?
아니면 디자인 + margin/padding 까지 고려해야 하는가?
아니면 디자인 + margin/padding + 부모요소 + 사용하는 함수?
프로젝트 할 때, 처음에는 디자인과 안의 구성 패턴이 같아서 공통 컴포넌트로 뒀는데 아니였다. 작은 차이는 영향이 없을 거라고 생각했는데,, 부모요소의 position 에 따라 margin/padding 이 달라지고 폰트가 바뀌고 개발하다가 추가 되는 기능들로 인해 추가되는 함수가 생겨버려서 prop에 점점 디테일한 요소가 추가된 결론까지 도달 했다.
유지보수를 위한 공통 컴포넌트가 유지보수성이 점점 떨어진다는 결론에 도달..
공통 컴포넌트 역할의
경계를 명확하게 하자
내가 가져온 예시 코드들은 카카오 기술 블로그의 예시와 GPT에게 물어본 추가 코드들이다.
Bad Example은 내가 프로젝트에서 짠 코드다.ㅎ
암튼
공통 컴포넌트의 목적은 "코드를 재사용해서 개발 속도와 유지보수를 쉽세 만드는 것"이다.
그런데 너무 범용적으로 만들면, 매번 많은 props를 줘야 해서 복잡해진다.
예시를 버튼으로 들어 역할을 나누면

// BaseButton.tsx
import cn from "classnames";
interface Props {
className?: string;
children: React.ReactNode;
}
export default function BaseButton({ className, children }: Props) {
return <button className={cn("base-button", className)}>{children}</button>;
}
// BrandButton.tsx
import BaseButton from "./BaseButton";
const brandStyles = {
naver: "bg-[#03c75a] text-white",
kakao: "bg-[#fee500] text-[#3c1e1e]",
google: "bg-white border text-gray-700",
};
interface BrandButtonProps {
brand: keyof typeof brandStyles;
children?: React.ReactNode;
onClick?: () => void;
}
export default function BrandButton({ brand, children, onClick }: BrandButtonProps) {
return (
<BaseButton onClick={onClick} className={brandStyles[brand]}>
{children || `${brand}로 로그인`}
</BaseButton>
);
}
호출시
<BrandButton brand="naver" />
<BrandButton brand="kakao" />
<BrandButton brand="google">Google Login</BrandButton>
// LoadingButton.tsx
export default function LoadingButton({ loading, children }) {
return (
<BaseButton className="loading-btn">
{loading ? "Loading..." : children}
</BaseButton>
);
}
https://tech.kakaoent.com/front-end/2024/240116-common-component/
https://developer.apple.com/documentation/uikit/uicollectionviewcompositionallayout
https://tech.kakaoent.com/front-end/2022/220505-how-page-part-use-atomic-design-system/