이번엔 프로젝트에서 많이 사용하는 Icon 컴포넌트를 리팩토링한 경험을 공유해 보려고 합니다.
SVG 아이콘을 쉽게 사용할 수 있도록 배경색과 반경 조정, 동적 사이즈 스케일링을 추가했습니다!
기존 코드 문제 📖
기존 Icon 컴포넌트는 각각 아이콘을 렌더링 하는 기능만 가지고 있었습니다.
❗문제점
1. 중복되는 코드가 너무 많았고 유지보수가 어려운 점
2. 사용자가 `배경색`와 `반경 설정`을 하려면 새로운 컴포넌트를 생성해서 사용해야 한다는 점에서 일관적인 스타일링의 어려움
3. SVG 사이즈 조정 시 배경만 커지는 문제
다양한 사이즈를 사용하는 UI에서 큰 문제였습니다.
리팩토링 📖
기존 Icon 컴포넌트
// AlbumIcon.tsx
export const AlbumIcon = () => {
return (
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="...."
fill=black
/>
</svg>
);
};
리팩토링 후 Icon 컴포넌트
다양한 아이콘을 하나의 `Icon` 컴포넌트로 관리할 수 있도록 코드를 수정했습니다.
import { ICONS } from '@/constants/icons';
interface IconProprType {
name: keyof typeof icons;
size?: number;
color?: string;
bgColor?: string;
rx?: string;
}
const Icon = ({ name, size = 28, color = 'black', bgColor, rx }: IconProprType) => {
const icon = ICONS[name];
// 사이즈 동적 조절
const scale = size >= 28 ? size / 28 : 1;
return (
<svg
width={size}
height={size}
viewBox={`0 0 ${size} ${size}`}
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="flex items-center justify-center"
>
{bgColor && <rect width={size} height={size} rx={rx} fill={bgColor} />}
<g transform={`scale(${scale})`}>
<path fillRule="evenodd" clipRule="evenodd" d={icon} fill={color} />
</g>
</svg>
);
};
export default Icon;
`Icon`의 `name`속성에 따라 원하는 아이콘의 path를 동적으로 렌더링 할 수 있게 수정했습니다.
const icon = ICONS[name];
// ✨ path 동적 렌더링
<path fillRule="evenodd" clipRule="evenodd" d={icon} fill={color} />
해당 path는 상수로 관리했습니다.
// constants/icons.ts
// ✨ path 상수로 관리
export const ICONS = {
AlbumIcon:
'M4 6C4 4.89543 4.89543 4 6 4H18C19.1046 4 20 4.89543 20 6V9H22C23.1046',
BellIcon:
'M20 13C20 10.3405 18.2697 8.08514 15.8734 7.29827C15.5892 6.53984 14.8577',
...
...
};
`bgColor`와 `rx`속성을 추가해 배경색과 아이콘 반경을 조정할 수 있도록 했습니다.
{bgColor && <rect width={size} height={size} rx={rx} fill={bgColor} />}
사이즈를 지정하면 path의 크기를 자동으로 조정하게 수정해 사이즈별로 추가 설정을 하지 않아도 되게 수정했습니다.
// ✨ 사이즈 동적 조절
const scale = size >= 28 ? size / 28 : 1;
return (
<svg
width={size}
height={size}
viewBox={`0 0 ${size} ${size}`}
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="flex items-center justify-center"
>
{bgColor && <rect width={size} height={size} rx={rx} fill={bgColor} />}
<g transform={`scale(${scale})`}>
<path fillRule="evenodd" clipRule="evenodd" d={icon} fill={color} />
</g>
</svg>
);
코드 사용 예시
// ✨ name은 필수! size와 color는 지정하지 않으면 기본값 적용
<Icon name="ArrowIcon" />
// ✨ 배경 색상과 반경 설정을 넣으면 뒷 배경이 변경
<Icon name="TimeIcon" size={32} color="white" bgColor="#00688A" rx="16" />
좋아진 점 😁
`중복 제거` : 단일 Icon 컴포넌트에서 아이콘을 관리할 수 있게 되어 코드가 간결해졌습니다.
`배경, 반경 속성 추가` : bgColor와 rx값을 통해 더 많은 스타일링이 가능합니다.
`크기 조정 문제 해결` : transform: scale()을 사용해 path 크기가 동적으로 조절이 가능합니다.
어려웠던 점 ❓
사이즈 동적 조절
단순히 중복된 코드만 하나로 합치면 된다고 생각했지만 리팩토링 후 테스트 하는 과정에서 여러 문제가 발생했었습니다.
배경색, 반경, 사이즈 조절까지 생각을 하지 못했던 점이 리팩토링 과정에서 어려운 문제점이었습니다.
회고 🧐
Icon 컴포넌트의 코드 중복을 줄이고 재사용 가능하게 하고 디자인의 일관성과 유지보수가 더 쉬워진 점에서 중요한 리팩토링이었다고 생각합니다.
'공부 > Next' 카테고리의 다른 글
[성능 최적화] Next.js HydrationBoundary를 활용한 서버-클라이언트 데이터 최적화 (0) | 2024.11.16 |
---|---|
Supabase에서 타입 설정하기 (0) | 2024.11.11 |
[리팩토링] queries 폴더 구조 변경 및 메서드명 수정 (1) | 2024.11.07 |
Next 커스텀 훅을 사용한 모달창 기능 구현 (1) | 2024.11.01 |
[리팩토링] 데이터 로직 분리 및 서버 상태 관리 최적화 (0) | 2024.10.28 |
Next 카카오맵을 활용한 시도별 가로 스크롤 버튼 이동 구현 (0) | 2024.10.28 |
[리팩토링] Next 카카오 맵 폴리곤 렌더링 리팩토링 - 커스텀 훅, 유틸 함수 구조 개선 (0) | 2024.10.24 |
Next 카카오 맵 행정구역 나누기 (1) | 2024.10.23 |