React의 다양한 라이브러리 중에 아이콘을 편하게 사용할 수 있도록 지원해 주는 라이브러리가 있어요!
Lucide React, Radix Icon을 컴포넌트처럼 사용하는 방법을 알려드릴게요.
아이콘을 사용할 때마다 아이콘의 이름을 매번 import 하는 것이 너무 싫었어요.
하나의 컴포넌트에서 다양한 아이콘을 사용한다면 import 한 아이콘들의 이름이 길어질 상황이 예상되었어요.
import { Camera } from 'lucide-react';
const App = () => {
return <Camera color="red" size={48} />;
};
export default App;
import { FaceIcon, ImageIcon, SunIcon } from '@radix-ui/react-icons'
function MyComponent () {
return (
<div>
<FaceIcon />
<SunIcon />
<ImageIcon />
</div>
)
}
분명히 저처럼 생각하는 사람들이 있을것 같았고 공식 라이브러리에서 지원을 해줄 것이라고
생각하고 공식문서를 더 찾아봤어요 역시 컴포넌트처럼 사용할 수 있는 방법이 있었어요
atom 폴더에 icons라는 폴더를 만들고 세 가지의 파일을 만들었어요.
LocalIcon.tsx : 로컬의 이미지를 이용한 아이콘 컴포넌트
LucideIcon.tsx : LucideIcon 컴포넌트
RadixIcon.tsx : RadixIcon 컴포넌트
className으로 스타일을 주고 있는 건 이번 프로젝트에서는 tailwindCSS를 적용해서 className으로 스타일을 주고 있어요
import { HTMLAttributes } from 'react';
export interface LocalIconProps extends HTMLAttributes<HTMLSpanElement> {
iconSrc: string;
iconSize?: number;
onClick?: (e: React.MouseEvent<HTMLSpanElement, MouseEvent>) => void;
className?: string;
onPointerDown?: (e: React.PointerEvent<HTMLSpanElement>) => void;
}
const LocalIcon = ({
iconSrc,
iconSize = 16,
onClick,
onPointerDown,
className,
...props
}: LocalIconProps) => {
const defaultStyle: React.CSSProperties = {
display: 'inline-block',
flexShrink: 0,
background: `url(${iconSrc}) center center/contain`,
backgroundRepeat: 'no-repeat',
width: `${iconSize}px`,
height: `${iconSize}px`,
};
return (
<span
className={className}
onClick={onClick}
onPointerDown={onPointerDown}
style={
onClick || onPointerDown
? { cursor: 'pointer', ...defaultStyle }
: { ...defaultStyle }
}
{...props}
/>
);
};
export default LocalIcon;
import { cn } from '@/src/lib/utils';
import colorSet, { ColorType } from '@/src/styles/color';
import { icons } from 'lucide-react'; <------ lucide import
import { HTMLAttributes } from 'react';
export interface LucideIconProps extends HTMLAttributes<HTMLOrSVGElement> {
name: keyof typeof icons;
color?: ColorType;
size?: number;
}
const LucideIcon = ({
name,
color = 'gray9',
size = 16,
...props
}: LucideIconProps) => {
const SelectLucideIcon = icons[name];
const isClickEvent = !!props.onClick;
const pointerStyle = isClickEvent ? 'cursor-pointer' : '';
return (
<SelectLucideIcon
color={colorSet[color]}
size={size}
className={cn(pointerStyle, props.className)}
{...props}
/>
);
};
export default LucideIcon;
import React from 'react';
import * as icons from '@radix-ui/react-icons'; <------ Radix Icon 컴포넌트 import
import { IconProps } from '@radix-ui/react-icons/dist/types';
import { cn } from '@/src/lib/utils';
import colorSet, { ColorType } from '@/src/styles/color';
export interface RadixIconProps extends IconProps {
name: keyof typeof icons;
size?: number;
color?: ColorType;
}
function RadixIcon({
name,
size = 16,
color = 'gray9',
...props
}: RadixIconProps) {
const SelectRadixIcon = icons[name];
const isClickEvent = !!props.onClick;
const pointerStyle = isClickEvent ? 'cursor-pointer' : '';
return (
<SelectRadixIcon
width={size}
height={size}
className={cn(pointerStyle, props.className)}
{...props}
color={colorSet[color]}
/>
);
}
export default RadixIcon;
LucideIcon, RadixIcon 컴포넌트 사용 시에 이름값을 추론해 주어서 편하게 사용할 수 있어요
LocalIcon
<LocalIcon
iconSrc={ClearSvg}
iconSize={16}
onPointerDown={() => {
onClear?.();
setValue('');
}}
/>
LucideIcon
<LucideIcon
size={16}
name="Calendar"
color={triggerProps?.disabled ? 'gray6' : 'gray9'}
className="flex flex-shrink-0"
/>
RadixIcon
<RadixIcon
size={16}
color="gray5"
name="InfoCircledIcon"
className="flex flex-shrink-0"
/>