画像にはいくつかの形式があります。SVGは拡大しても画質が劣化しないという利点があります。CSSでスタイルを設定でき、ファイルが小さいため、Webサイトの性能改善にも役立ちます。React NativeでもSVG画像を使えます。この記事では、React Native(Expo)での使い方を説明します。
react-native-svgをインストールする 🔗
👨💻
このライブラリはExpo Goに含まれているので、Expo環境で追加のインストールは不要です。
Expoを使わないReact Nativeプロジェクトでは、
react-native-svg をインストールします。次のコマンドを使います。
npm install react-native-svg
react-native-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 は、react-native-svg が提供するコンポーネントです。Svg 内で Circle と Line を使い、SVGコードを変換します。次は変換後のコードです。
/assets/image/example.tsximport 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.tsximport 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をコンポーネントに変換するWebサイトもあります。
React SVGR↗にSVGコードを貼り付けると、Reactコンポーネントに変換されます。SVGを手作業で書き換える必要はありません。上の例をReact SVGRで変換した結果は次のとおりです。
/assets/image/example-svgr.tsximport * 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.tsdeclare module '*.svg' {
import React from 'react';
import { SvgProps } from 'react-native-svg';
const content: React.FC<SvgProps>;
export default content;
}
これでSVG画像を直接インポートできます。assets フォルダーにSVGファイルを追加し、使うときは require 関数でファイルパスを読み込みます。次は使用例です。
/app/index.tsximport 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 を渡すと、SVGのスタイルを変更できます。次の例では、SVGのfill属性に fill prop、stroke属性に stroke propの値を渡します。色を可変にするには「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.tsximport { 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画像を使う場合には、どんな利点と欠点があるでしょうか。