最近新しい趣味を始めようと、前々から欲しかった車を買いました。
みなさんこんにちは、ソリューション技術部の隈本(クマモト)です。
今回は弊社でも新しい試みであるReact Nativeのお話です。
React Nativeを触ったことあるみなさんは、その中でもスタイリングについてどのようにされていますか?
サンプルコードによくあるようにコンポーネント内にスタイルを記述しますか?それともスタイル用のファイルを用意しますか?それともウルトラCな方法で記述してますか?
もしウルトラCをご存知の方がいれば教えてください。
今回私がReact Nativeの案件を進めるにあたり、実際に対応したスタイリングについてお話ししようと思います。
今後のReact Nativeのスタイリングの参考になれば幸いです。
- 結論
- React Nativeとは
- 基本的なReact Nativeのスタイリング
- SCSSを利用したスタイリング
- React NativeのスタイリングとSCSSを利用したReact Nativeのスタイリングを見比べてみる
- 共通化してみる
- 導入方法
- まとめ
結論
論より証拠ということで結論を先に簡単に提示しておきましょう。
SCSSをReact Nativeで利用できるモジュールを使用し、必要なスタイルを共通化しつつ既存のWebサービスのスタイルと整合性が取りやすいようにする。
Nodeモジュールの react-native-sass-transformer
を使用して、React Native内でSCSSを利用していきます。
React Nativeとは
そもそもReact Nativeってなぁに?って方もいると思うので、簡単に解説します。
実際私も今回のタスクで初めて触りましたので、まだまだ初心者です。
Create native apps for Android, iOS, and more using React
React Native combines the best parts of native development with React, a best-in-class JavaScript library for building user interfaces. *1
つまりは、モバイルアプリ(iOS, Android)の開発をReactベースで行えるという画期的なフレームワークです。
ネイティブアプリの知識がなくても、React(JavaScript)の知識を持っていれば、同じようにネイティブアプリの開発ができるようになっています。
例えば下記のようなReactのソースをReact Nativeで書き直してみます。
React
import "./styles.css"; export default function App() { return ( <div className="App"> <h1>Hello React</h1> <h2>Start editing to see some magic happen!</h2> <p>これはReactで記述されています。</p> </div> ); }
React Native
import { Text, SafeAreaView, StyleSheet } from 'react-native'; export default function App() { return ( <SafeAreaView style={styles.container}> <Text style={styles.h1Text}>Hello React Native</Text> <Text style={styles.h2Text}>Create native apps for Android, iOS, and more using React</Text> <Text>これはReact Nativeで記述されています。</Text> </SafeAreaView> ); } const styles = StyleSheet.create({ container: { justifyContent: 'center', alignItems: 'center', }, h1Text: { fontSize: 40, }, h2Text: { fontSize: 20, } });
最終的な見た目の若干の差異はありますが、基本的なロジックの部分の記述はReactを踏襲しているため、書きっぷりがとても似ています。
基本的なReact Nativeのスタイリング
決定的に異なるのは下記のスタイリングに関する部分です。
const styles = StyleSheet.create({ container: { justifyContent: 'center', alignItems: 'center', }, h1Text: { fontSize: 40, }, h2Text: { fontSize: 20, } });
React Nativeでは基本的にコンポーネント内で、そのコンポーネントに対するスタイリングを記述していきます。
しかしながら、開発の規模が大きくなってくるとこのお作法ではコードの品質が悪くなってしまう可能性が非常に高いです。
なぜなら、コンポーネントを作成するエンジニアによってキー名の定義であったり、共通化できるスタイルが乱立したりと保守性が失われてしまうからです。
SCSSを利用したスタイリング
今回私が担当した案件は、もともとWebで利用されているサービスをReact Nativeでもアプリ化するというものでした。
また、見た目も既存のWebアプリを踏襲する流れだったため、開発スピードや保守性の観点からも、SCSSを利用してスタイリングする、もしくはSCSSライクな方法でスタイリングができないかと模索しておりました。
そこで利用することになったのがNodeモジュールの react-native-sass-transformer
です。
このモジュールはReact Native環境でもSCSS(Sass)を利用できるようにするというもので、今回の案件ではピッタリでした。
その中で私が感じたメリットをご紹介します。
- 従来のWebのスタイルがほぼそのまま使える
- SCSS特有の変数が利用できる
@import
や@extend
が利用できる
etc...
特に今回はサービスのテーマカラーや共通margin等が共通ファイルとして元々定義されていたので、それが流用できることでReact Native環境で再定義することなく利用できたのが大きかったです。
React NativeのスタイリングとSCSSを利用したReact Nativeのスタイリングを見比べてみる
実際にReact Native標準のスタイリングとSCSSを利用したReact Nativeのスタイリングを見比べてみましょう。
実際に試せるように以下にサンプルアプリを作成しました。
超簡単なサンプルでテキストのスタイリングを、通常のスタイリングとSCSSを利用した場合とで作成しました。
コンポーネントのソースコードはこちらです。
上側の「これは通常のスタイリングです。」がReact Nativeのデフォルトの機能のみでスタイリングしたものになり、下側がSCSSを利用しているものになります。
これくらいのものであれば通常のスタイリングでもいいかもしれません。
しかし、プロジェクトが大きくなっていったり、複数人で開発したりする場合ではスタイルの共通化や記述のルールが必要になる場面もあるでしょう。
そこで次はスタイルファイルを共通化してみます。
共通化してみる
SCSSファイルをよく使うスタイル設定やコンポーネント等の決まった部品ごとに共通化することで、実装の手間を減らしたりコードの統一化を図ることができます。
こちらもサンプルアプリを組み込んでみました。
通常のスタイリング | SCSSを利用したスタイリング |
---|---|
このアプリではモーダルの中のコンポーネントではスタイリングのオブジェクトのキー名を統一しています。(styles.hogehoge
のhogehoge
にあたる部分)
よってソース的な差分はスタイル部分のみとなります。
通常スタイルの記法とSCSSを利用した記法両方において同一のスタイリングが可能であることがわかりますね。
また、共通化している部分としてはこちらのファイルに記載されている内容で、テキスト周りやコンテナの大枠のスタイリングを決めています。
導入方法
最後に導入方法を記載いたします。
基本的には公式ドキュメントに記載されている方法で完結します。
手順
1. インストールコマンドを叩く
yarn add --dev react-native-sass-transformer sass
2. metro.config.js
の記述を変更する。
今回私が作成したサンプルアプリでは下記のような内容になります。
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); /** * Metro configuration * https://reactnative.dev/docs/metro * * @type {import('metro-config').MetroConfig} */ const config = { transformer: { getTransformOptions: async () => ({ transform: { experimentalImportSupport: false, inlineRequires: true, }, }), } }; const { resolver: { sourceExts }, } = getDefaultConfig(__dirname); const sassConfig = { transformer: { babelTransformerPath: require.resolve('react-native-sass-transformer'), }, resolver: { sourceExts: [...sourceExts, 'scss', 'sass'], }, }; module.exports = mergeConfig(getDefaultConfig(__dirname), config, sassConfig);
3. app.json
に下記を追記します。
"packagerOpts": { "config": "metro.config.js", "sourceExts": ["js", "jsx", "scss", "sass"] }
まとめ
今回初めてのReact Native案件で初めてのSCSS導入をしてみましたが、そこまで障壁となるようなこともなく、実装しつつスタイルを構築しつつあります。
大規模案件になればなるほど、共通化や既存コードをうまく活用したコーディング等が開発スピードやクオリティに大きく関わってくることも多いでしょう。
もし、この記事が読んでくださったみなさんの何かの参考になれば幸いです。
また、もっとこうしたほうがいいとかこういう方法もあるだとかのご意見もお待ちしております。
*1:React Native official site: https://reactnative.dev/