React | SVG 파일 효율적으로 활용해보자

ha ju·2021년 7월 6일
3
post-thumbnail
post-custom-banner

React | SVG 파일 효율적으로 활용해보자

프로그래머스 웹페이지를 클론하면서 여러 이미지를 활용해야하는 부분이 있었다.
처음에는 스타일드 컴포넌트 아이콘 라이브러리를 활용하려 했지만 내가 아는 선에서는 스타일드 컴포넌트 아이콘을 사용하면 코드가 너무 비효율적이어질 것 같은 느낌..
일단 필요한 이미지들의 svg 파일들을 다운받긴했는데.. 그 당시에는 이미지 태그의 소스로 사용하는 법밖에 몰랐던 svg 초짜.. svg를 제대로 사용해보자 라는 생각으로 대략 3일을 내내 이 로직을 짜고 svg 파일을 효율적으로 활용하는 법에 대해 매달려 있었다..

🌻 여러 시행착오들과 최종적으로 나온 코드를 소개하려한다!



🍀 첫 번째 시도

  • Img 태그에서 src에 svg 파일 경로 삽입. but,, background-color는 넣을 수 있지만 실제 색깔제어 못한다는 한계점에 봉착했다. 처음에는 호버되면 색깔 바뀌는 기능 없는 척ㅇㅅㅇ; 하고 싶었지만 svg 널 뽀개주겠어.. 하고 리팩토링을 시작
<Languages value={questionData.programming_language}>
          {questionData &&
            questionData.programming_language.map((lang, index) => (
              <LanguageIcons key={index}>
                <ToolTip name={lang.name} hoverIcon={hoverIcon}>
                  {lang.name}
                </ToolTip>
                <LanguageIcon
                  value={lang.id}
                  name={lang.name}
                  alt={lang.name}
                  src={`/image/languageImgSrc/${
                    lang.name === 'C#' ? 'CSharp' : lang.name
                  }.svg`}   // ⭐ 그저.. img태그의 src 속성으로 제어해주려했던 어리석은 과거
                  onMouseEnter={() => {
                    setHoverIcon(lang.name);
                  }}
                  onMouseLeave={() => {
                    setHoverIcon();
                  }}
                />
              </LanguageIcons>
            ))}
        </Languages>


🍀🍀 두 번째 시도

  • 선경님 블로그 보고 얻은 힌트로 시작!!일단 모든 svg 파일을 컴포넌트로 임포트 해준다
import { ReactComponent as 아이콘컴포넌트명 } from ‘경로’ 
  • <svg> 태그 내에서 변경 해주고싶은 스타일 속성들은 모두 current 값으로 바꿔준다. (width, height, fill 등을 current로 바꿔주었다!)
    - 📌 여기서 <svg> 태그 하위에 path 태그가 여러개가 있고 fill 속성이 각각 들어있는 것이 있기 때문에 fill 값 모두 확인하고 넣어주자. 그렇지 않으면 그림 중 한곳만 띠용하게 다른 색깔이 들어가게된다.
  • 각각 문제에 들어오는 프로그래밍 언어 데이터를 배열형태로 만들어주었다
    해당 프로그래밍 언어("C++")가 있을때에만 아이콘이 렌더되도록 하기때문이다.
const langData = questionData.programming_language.map(lang => lang.name);

console.log(langData)   // ["C","C++","Java"] 
  • 이 배열에 값이 들어있다면 렌더되도록하고 아니면 display:none이 되도록 했더니 아래와 같이 매우 비효율적인 코드가 탄생했다..
 display: ${props =>
    props.langData.includes(props.name) ? 'inline-flex' : 'none'};    
//스타일드 컴포넌트로 langData배열에 그 값이 있으면 렌더 아니면 안보이도록 스타일링

🤯 어떻게 리팩토링 할 수 있을지 고민 🤯
반복되는 코드들과 하드코딩한 코드들이 많아서 어떻게 줄일 수 있을까.. 맘같아선 위에서 도출한 langData 배열을 활용해서 맵을 돌리고 싶지만 svg 파일을 컴포넌트로 import해주었기 때문에 컴포넌트태그를 쓸 때 조건부로 줄 수 없었다...



🍀🍀🍀 세 번째 시도

갓 은정님의 피드백으로 리팩토링 할 수 있었다!!!
리팩토링 과정을 요약해서 말하자면,

  • 필요한 전체 이미지를 총 관리 해주는 컴포넌트를 만든다
  • 각각의 <svg> 태그를 리턴하도록하는 함수를 value값으로 가지는 객체를 만들어준다
  • 이 객체에서 필요한 key 값에 접근하여 함수를 호출 하면 내가 원하는 이미지만 상위 컴포넌트에서 렌더할 수 있는 것이다!!

 const languageSvgObj = {
    C: () => (
      <svg
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 128 128"
        width="current"
        height="current"
      >
        <path
          fill="current"
          d="M117.5 33.5l.3-.2c-.6-1.1-1.5-2.1-2.4-2.6l-48.3-27.8c-.8-.5-1.9-.7-3.1-.7-1.2 0-2.3.3-3.1.7l-48 27.9c-1.7 1-2.9 3.5-2.9 5.4v55.7c0 1.1.2 2.3.9 3.4l-.2.1c.5.8 1.2 1.5 1.9 1.9l48.2 27.9c.8.5 1.9.7 3.1.7 1.2 0 2.3-.3 3.1-.7l48-27.9c1.7-1 2.9-3.5 2.9-5.4v-55.8c.1-.8 0-1.7-.4-2.6zm-53.5 55c9.1 0 17.1-5 21.3-12.4l12.9 7.6c-6.8 11.8-19.6 19.8-34.2 19.8-21.8 0-39.5-17.7-39.5-39.5s17.7-39.5 39.5-39.5c14.7 0 27.5 8.1 34.3 20l-13 7.5c-4.2-7.5-12.2-12.5-21.3-12.5-13.5 0-24.5 11-24.5 24.5s11 24.5 24.5 24.5z"
        />
      </svg>
    'C#': () => (...)      
      .
      .
      .
                 
return (
    <LanguageSvgContainer hover={name === hoverIcon}>
      {languageSvgObj[name]()}  //⭐객체의 key 값으로 접근하여 함수를 호출해준다
    </LanguageSvgContainer>
  ); 
   // 여기서 name,hoverIcon 이라는 props는 호버 시 툴팁 생성을 위해 상위 컴포넌트에서 받아주었다
   //name (렌더링할 프로그래밍 언어를 문자열로 넘겨줌)
   //hoverIcon(onMouseEnter 시, 해당 프로그래밍 언어를 hoverIcon 라는 state에 문자열로 저장)
      


배운점

위의 과정을 통해 배운 것 중 가장 중요한 것은 객체를 통해 재사용 가능한 함수 형태를 만들어주었고 그것을 활용해서 svg 이미지들을 효율적으로 사용해주었다는 것!

post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 7월 8일

마지막방법같은경우 margin 같은 스타일은 어떻게 적용시켜야한가요?

답글 달기