Vite + React + TS의 동적 SVG 구성 요소

vite에 대한 놀라운 이야기를 많이 들은 후 나는 그것을 시도하고 무언가를 만들기로 결정했으며 DX에 전혀 실망하지 않았습니다. 그래서 내가 이 재미있는 내 프로젝트(현재 WIP)를 개발할 때 SVG 아이콘 이름과 내가 제어할 수 있는 모든 SVG 사용자 지정 속성을 제공하기만 하면 로드되는 동적 SVG 구성 요소를 만드는 것을 생각했습니다.

첫 번째 장애물은 CRA에서와 같이 SVG를 React 구성 요소로 변환할 수 있는 플러그인을 찾는 것이었습니다. 몇 번의 Google 검색 후 vite-plugin-svgr에 도달했습니다.

vite-plugin-svgr을 설치합니다.



React 프로젝트에 CRA를 사용하는 경우 내부에서 구성SVGR(SVGR을 사용하면 SVG를 React 구성 요소로 변환할 수 있음)하므로 이 단계를 건너뛸 수 있습니다.

플러그인을 설치하려면 다음을 실행하십시오.
yarn add -D vite-plugin-svgr

vite-plugin-svgr 설정:



설치된 플러그인을 vite config 파일에 등록하세요.

파일: vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import svgr from "vite-plugin-svgr"; // transform svg to react component

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react(), svgr()], // register the plugin
});


사용자 지정 후크 작성:



SVGR 설정이 완료되면 아이콘 이름을 가져와 자산에서 가져와서 로드하는 기능을 만들 준비가 된 것입니다. 아이콘의 경로를 가져와 로드할 수 있도록 후크를 수정할 수도 있습니다. 이 후크에서 로드 상태, 오류 상태 및 구성 요소 자체를 내보냅니다.

파일: useDynamicSvgImport.ts
import React, { useEffect, useRef, useState } from "react";

export function useDynamicSvgImport(iconName: string) {
  const importedIconRef = useRef<React.FC<React.SVGProps<SVGElement>>>();
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<unknown>();

  useEffect(() => {
    setLoading(true);
    // dynamically import the mentioned svg icon name in props
    const importSvgIcon = async (): Promise<void> => {
      // please make sure all your svg icons are placed in the same directory
      // if we want that part to be configurable then instead of iconName we will send iconPath as prop
      try {
        importedIconRef.current = (
          await import(`../../assets/icons/${iconName}.svg`)
        ).ReactComponent; // svgr provides ReactComponent for given svg path
      } catch (err) {
        setError(err);
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    importSvgIcon();
  }, [iconName]);

  return { error, loading, SvgIcon: importedIconRef.current };
}


구성 요소 작성:



SVG용 래퍼 구성 요소를 작성해 보겠습니다. 이 래퍼의 주요 목표는 아이콘이 표시되지 않을 때 로딩 시머를 제공하고 일부 래퍼 스타일과 SVG 속성을 적용하는 것입니다.

파일: SvgIcon.tsx
import { useDynamicSvgImport } from "./useDynamicSvgImport";

interface IProps {
  iconName: string;
  wrapperStyle?: string;
  svgProp?: React.SVGProps<SVGSVGElement>;
}

function SvgIcon(props: IProps) {
  const { iconName, wrapperStyle, svgProp } = props;
  const { loading, SvgIcon } = useDynamicSvgImport(iconName);

  return (
    <>
      {loading && (
        <div className="rounded-full bg-slate-400 animate-pulse h-8 w-8"></div>
      )}
      {SvgIcon && (
        <div className={wrapperStyle}>
          <SvgIcon {...svgProp} />
        </div>
      )}
    </>
  );
}

export default SvgIcon;


구성 요소 사용:



이제 구성 요소를 소품으로 전달할 수 있는 모든 SVG 요소 특성 및 래퍼 스타일과 함께 사용할 준비가 되었습니다.

파일: App.tsx
import './App.css';
import SvgIcon from './SvgIcon';

function App() {
  return (
    <div>
      <h1>Hello!</h1>
      <SvgIcon
        iconName="react"
        svgProp={{ width: 100, height: 100, fill: "#61dafb" }}
      />
      <SvgIcon iconName="react" svgProp={{ stroke: "white", fill: "blue" }} />
    </div>
  );
}

export default App;



작동 예제 링크:





아래 의견에 더 좋은 방법이 있으면 알려주십시오.
읽어주셔서 감사합니다. 당신이 그것을 좋아한다면 몇 가지 ❤️ 또는 🦄를 떨어 뜨립니다.

좋은 웹페이지 즐겨찾기