React에서 SVG를 사용중이였다.(styled-components 사용중.) 그런데 여러 SVG를 사용하는 상황에서 여러 SVG모두 같은 css를 받던 상황이였다. (심지어 props에대한 로직도 같은 상황)
//style.ts
...
export const Icon = styled(HomeSVG)<PropTypes>`
> path {
stroke: ${(props) => {
return (props.selected ? mainColor : greyFontColor)}};
}
${mobileQuery}{
width: 24px;
height: 24px;
}
export const Icon = styled(AnotherSVG)<PropTypes>`
> path {
stroke: ${(props) => {
return (props.selected ? mainColor : greyFontColor)}};
}
${mobileQuery}{
width: 24px;
height: 24px;
}
export const Icon = styled(Another2SVG)<PropTypes>`
> path {
stroke: ${(props) => {
return (props.selected ? mainColor : greyFontColor)}};
}
${mobileQuery}{
width: 24px;
height: 24px;
}
.....
styled-components에서 해당 SVG컴포넌트들에 동일하게 스타일을 주기엔 코드중복이 보이던 문제가 있었다.
이 문제는 styled-components의 as
를 이용해 해결했다.!
import HomeSVG from '@assets/svg/home.svg';
import ClipBoardCheckSVG from '@assets/svg/clipboard-check.svg';
import DocumentTextSVG from '@assets/svg/document-text.svg';
import TemplateSVG from '@assets/svg/template.svg';
import UserSVG from '@assets/svg/user.svg';
다섯개의 SVG를 받아오고있었고 이 SVG들은 모두 같은 스타일링을 할 것이다.
const options = [
{ title: '홈', path: '/', svg : HomeSVG },
{ title: '강의평', path: '/lectures', svg : ClipBoardCheckSVG },
{ title: '강의자료', path: '/materials', svg :DocumentTextSVG },
{ title: '시간표', path: '/timetables', svg : TemplateSVG },
{ title: '마이페이지', path: '/mypage', svg : UserSVG },
];
const BottomNav : React.FC = () => (
<NavContainer>
{options.map((option) => (
<EachOption
key={option.title}
title={option.title}
path={option.path}
svg={option.svg}
/>
))}
</NavContainer>
);
각각의 svg를 props로받는 EachOption컴포넌트들은
<Icon as={svg} selected={path === router.pathname}/>
이 styled-components를 리턴한다.
as
를이용하면 Icon컴포넌트가 어떤 tag를 가르키든 Icon 컴포넌트는 as가 가르키는 tag가 된다.
//style.ts
export const Icon = styled.svg<PropTypes>`
> path {
stroke: ${(props) => {
return (props.selected ? mainColor : greyFontColor)}};
}
${mobileQuery}{
width: 24px;
height: 24px;
}
Icon컴포넌트의 tag는 svg로 설정은하였지만 h1이던 div든 .. 뭐든 상관없다. 어짜피 as가 가르키는 string tag로 변경이 되기 때문이다.
<SVG />
와 SVG
차이를 몰라서 자꾸 에러가나서 힘들었다. console에 두개를 모두 찍어보면
//console.log(SVG)
ƒ SvgHome(props) {
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("svg", _extends({
xmlns: "http://www.w3.org/2000/svg",
fill: "none",
viewBox: "0 0 24 24"
}, p…
//console.log(<SVG />)
{$$typeof: Symbol(react.element), key: null, ref: null, props: {…}, type: ƒ, …}
즉, SVG
는 함수이다. 컴포넌트이므로 함수이다. <SVG />
는 SVG
의 리턴값인 객체이다. 이는 JSX인 것이고 JSX는 객체이다.(왜냐면 JSX는 React.craeteElement()
로 트랜스파일링되고 React.createElement()
는 객체를 리턴하기때문에 <SVG />
는 객체이다. 여기서 리턴되는 객체는 React 엘리먼트라고 한다.)
그러므로 SVG
는 JSX를 리턴하는 함수이고 <SVG />
는 리턴된 JSX이므로 <SVG />
는 하나의 만들어진 엘리먼트이다.
이 차이를 알고나면 어렵지 않은 문제였다.
SVG
와 <SVG />
는 각각 함수와 함수의 리턴된 값인 JSX, 즉 엘리먼트(객체)이다.as
를 이용하면 좀더 확장성 있는 컴포넌트의 작성이 가능하다.