이 글은 기본적인 Expo 프로젝트가 생성되어 있다고 가정합니다. Expo 프로젝트를 생성하는 방법은 Expo 프로젝트 생성:
윈도우 ,
Mac 을 참고해주세요.
이미지의 확장자는 여러가지가 있지만, SVG 이미지는 확장성이 좋아서 여러 크기로 확대해도 깨지지 않는 장점이 있습니다. 또한, SVG 이미지는 CSS로 스타일링이 가능하고, 파일 크기가 작아서 웹사이트의 성능을 향상시킬 수 있습니다. React Native에서도 SVG 이미지를 사용할 수 있습니다. 이 글에서는 React Native(Expo)에서 SVG 이미지를 사용하는 방법을 알아보겠습니다.
🚀
react-native-svg 라이브러리 설치 🔗
👨💻
이 라이브러리는 Expo Go에 포함되어 있기 때문에 Expo 환경에서는 추가적인 설치를 진행하지 않아도 됩니다.
Expo가 아닌 React Native 프로젝트에서는
react-native-svg
라이브러리를 설치해야 합니다. 다음 명령어를 통해 라이브러리를 설치합니다.
npm install react-native-svg
react-native-svg를 사용하면 상호작용과 애니메이션을 지원하여 앱에서 SVG를 사용할 수 있습니다.
먼저 svg 이미지를 다운받습니다. svg 파일을 열면 svg 코드를 확인할 수 있습니다. svg 코드를 복사합니다. 다음 예시는 svg에서 지원하는 circle, line 태그를 사용한 코드입니다.
/assets/image/example.svg (예시 svg 파일) < svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
< circle cx = "12" cy = "12" r = "10" />
< line x1 = "12" y1 = "8" x2 = "12" y2 = "16" />
< line x1 = "8" y1 = "12" x2 = "16" y2 = "12" />
</ svg >
예시 svg 파일
svg 코드를 복사한 후, Svg
컴포넌트를 사용하여 SVG 이미지를 사용할 수 있습니다. 이 때, Svg
컴포넌트는 react-native-svg
라이브러리에서 제공하는 컴포넌트입니다. Svg
컴포넌트 안에 Circle
, Line
컴포넌트를 사용하여 svg 코드를 변환합니다. 다음은 svg 코드를 변환한 코드입니다.
/assets/image/example.tsx import Svg, { Circle, Line } from 'react-native-svg' ;
export default function SvgComponent () {
return (
< Svg width = "100" height = "100" viewBox = "0 0 24 24" >
< Circle cx = "12" cy = "12" r = "10" fill = "none" stroke = "black" strokeWidth = "2" />
< Line x1 = "12" y1 = "8" x2 = "12" y2 = "16" stroke = "black" strokeWidth = "2" />
< Line x1 = "8" y1 = "12" x2 = "16" y2 = "12" stroke = "black" strokeWidth = "2" />
</ Svg >
);
}
이제 SvgComponent
컴포넌트를 사용하여 SVG 이미지를 화면에 렌더링할 수 있습니다.
/app/index.tsx import React from 'react' ;
import { View } from 'react-native' ;
import SvgComponent from './example' ;
export default function App () {
return (
< View style ={ { flex: 1 , justifyContent: 'center' , alignItems: 'center' } } >
< SvgComponent />
</ View >
);
}
SVG 이미지를 컴포넌트로 변환해주는 사이트도 있습니다.
React SVGR↗ 사이트에서 SVG 코드를 붙여넣으면 React 컴포넌트로 변환해줍니다. 이 사이트를 사용하면 SVG 코드를 직접 작성하지 않고도 React 컴포넌트로 변환할 수 있습니다. 위 예시 코드를 React SVGR 사이트에서 변환한 코드는 다음과 같습니다.
/assets/image/example-svgr.tsx import * as React from "react"
import Svg, { SvgProps, Circle, Path } from "react-native-svg"
const SvgComponent = ( props : SvgProps ) => (
< Svg
xmlns = "http://www.w3.org/2000/svg"
fill = "none"
stroke = "currentColor"
strokeLinecap = "round"
strokeLinejoin = "round"
strokeWidth ={ 2 }
viewBox = "0 0 24 24"
{... props }
>
< Circle cx ={ 12 } cy ={ 12 } r ={ 10 } />
< Path d = "M12 8v8M8 12h8" />
</ Svg >
)
export default SvgComponent
수동 변환한 코드와 조금 다르죠???
이 사이트를 이용하여 변환 시에
SvgProps
를 사용하여 props를 전달할 수 있습니다. 그렇기 때문에 저는 이 사이트를 사용하여 SVG 이미지를 컴포넌트로 변환하는 것을 추천합니다.
🚀
react-native-svg-transformer 사용하기 🔗
하지만 매번 SVG 코드를 컴포넌트로 변환하는 것은 파일 확장자를 변경하는 등 번거로운 작업이 필요합니다. 이 때 react-native-svg-transformer
라이브러리를 사용하면 SVG 파일을 자동으로 컴포넌트로 변환할 수 있습니다.
먼저 react-native-svg-transformer
라이브러리를 설치합니다.
npm install --save-dev react-native-svg-transformer
# yarn add --dev react-native-svg-transformer
➡️
metro.config.js 설정 추가 🔗
그 다음, 루트 폴더에 위치한 metro.config.js
파일을 수정하여 설정을 추가합니다. 일반 React Native 프로젝트에서는 metro.config.js
파일이 없을 수 있습니다. 이 때는 루트 폴더에 metro.config.js
파일을 생성하고 다음 설정을 추가합니다. module.exports 부분의 코드를 추가합니다.
metro.config.js (Expo 프로젝트 기준) /* eslint-env node */
const { getDefaultConfig } = require ( 'expo/metro-config' );
/** @type {import('expo/metro-config').MetroConfig} */
module . exports = (() => {
const config = getDefaultConfig (__dirname);
const { transformer , resolver } = config;
config.transformer = {
... transformer,
babelTransformerPath: require. resolve ( 'react-native-svg-transformer/expo' ),
};
config.resolver = {
... resolver,
assetExts: resolver.assetExts. filter (( ext ) => ext !== 'svg' ),
sourceExts: [ ... resolver.sourceExts, 'svg' ],
};
return config;
})();
metro.config.js (React Native 프로젝트 기준) const { getDefaultConfig , mergeConfig } = require ( "@react-native/metro-config" );
const defaultConfig = getDefaultConfig (__dirname);
const { assetExts , sourceExts } = defaultConfig.resolver;
/**
* Metro configuration
* https://reactnative.dev/docs/metro
*
* @type {import('metro-config').MetroConfig}
*/
const config = {
transformer: {
babelTransformerPath: require. resolve (
"react-native-svg-transformer/react-native"
)
},
resolver: {
assetExts: assetExts. filter (( ext ) => ext !== "svg" ),
sourceExts: [ ... sourceExts, "svg" ]
}
};
module . exports = mergeConfig (defaultConfig, config);
Typescript를 사용하는 경우,
declarations.d.ts
파일에 다음 설정을 추가합니다. 이 설정은 Typescript에서 svg 파일을 모듈로 인식할 수 있도록 도와줍니다.
파일이 없다면, 루트 폴더에
declarations.d.ts
파일을 생성하고 다음 설정을 추가합니다.
declarations.d.ts declare module '*.svg' {
import React from 'react' ;
import { SvgProps } from 'react-native-svg' ;
const content : React . FC < SvgProps >;
export default content;
}
이제 SVG 이미지를 직접 Import 하여 사용할 수 있습니다. assets
폴더에 SVG 파일을 추가하고, SVG 파일을 사용할 때는 파일 경로를 require
함수로 불러옵니다. 다음은 SVG 이미지를 사용하는 예시 코드입니다.
/app/index.tsx import React from 'react' ;
import { View } from 'react-native' ;
import SvgComponent from '@/assets/image/example.svg' ;
export default function App () {
return (
< View style ={ { flex: 1 , justifyContent: 'center' , alignItems: 'center' } } >
< SvgComponent />
</ View >
);
}
SVG 이미지의 속성을 props로 전달할 수 있습니다. 예를 들어, fill
, stroke
, strokeWidth
등의 속성을 props로 전달하여 SVG 이미지를 스타일링할 수 있습니다. 다음은 SVG 이미지의 속성을 props로 전달하는 예시 코드입니다. svg 코드의 fill 속성은 fill
props로 전달하고, stroke 속성은 stroke
props로 전달됩니다. 가변적인 색상을 전달받으려면 "currentColor"를 사용합니다.
/assets/image/example.svg < svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" fill = " currentColor " stroke = " currentColor " stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
< circle cx = "12" cy = "12" r = "10" />
< line x1 = "12" y1 = "8" x2 = "12" y2 = "16" />
< line x1 = "8" y1 = "12" x2 = "16" y2 = "12" />
</ svg >
이후 SVG 이미지를 사용할 때 props로 전달할 수 있습니다.
/app/index.tsx import { View } from 'react-native' ;
import SvgComponent from '@/assets/image/example.svg' ;
export default function App () {
return (
< View style ={ { flex: 1 , justifyContent: 'center' , alignItems: 'center' } } >
< SvgComponent fill ={ 'blue' } stroke ={ 'green' } width ={ 100 } height ={ 100 } />
</ View >
);
}
fill, stroke 속성 변경
이외에도 width
, height
, viewBox
등의 속성을 props로 전달할 수 있습니다.
SVG 이미지를 사용할 때의 장단점은 무엇인가요?