PLAY DEVELOPERS BLOG

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

大規模案件におけるReact Nativeでのスタイリング手法

最近新しい趣味を始めようと、前々から欲しかった車を買いました。

みなさんこんにちは、ソリューション技術部の隈本(クマモト)です。

今回は弊社でも新しい試みであるReact Nativeのお話です。

React Nativeを触ったことあるみなさんは、その中でもスタイリングについてどのようにされていますか?

サンプルコードによくあるようにコンポーネント内にスタイルを記述しますか?それともスタイル用のファイルを用意しますか?それともウルトラCな方法で記述してますか?

もしウルトラCをご存知の方がいれば教えてください。

今回私がReact Nativeの案件を進めるにあたり、実際に対応したスタイリングについてお話ししようと思います。

今後の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で記述したコード
Reactで記述したコード

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 Nativeで記述したコード
React Nativeで記述したコード

最終的な見た目の若干の差異はありますが、基本的なロジックの部分の記述は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 です。

www.npmjs.com

このモジュールはReact Native環境でもSCSS(Sass)を利用できるようにするというもので、今回の案件ではピッタリでした。

その中で私が感じたメリットをご紹介します。

  • 従来のWebのスタイルがほぼそのまま使える
  • SCSS特有の変数が利用できる
  • @import@extendが利用できる

etc...

特に今回はサービスのテーマカラーや共通margin等が共通ファイルとして元々定義されていたので、それが流用できることでReact Native環境で再定義することなく利用できたのが大きかったです。

React NativeのスタイリングとSCSSを利用したReact Nativeのスタイリングを見比べてみる

実際にReact Native標準のスタイリングとSCSSを利用したReact Nativeのスタイリングを見比べてみましょう。

実際に試せるように以下にサンプルアプリを作成しました。

github.com

超簡単なサンプルでテキストのスタイリングを、通常のスタイリングとSCSSを利用した場合とで作成しました。

テキストスタイルのサンプル

コンポーネントのソースコードはこちらです。

上側の「これは通常のスタイリングです。」がReact Nativeのデフォルトの機能のみでスタイリングしたものになり、下側がSCSSを利用しているものになります。

これくらいのものであれば通常のスタイリングでもいいかもしれません。

しかし、プロジェクトが大きくなっていったり、複数人で開発したりする場合ではスタイルの共通化や記述のルールが必要になる場面もあるでしょう。

そこで次はスタイルファイルを共通化してみます。

共通化してみる

SCSSファイルをよく使うスタイル設定やコンポーネント等の決まった部品ごとに共通化することで、実装の手間を減らしたりコードの統一化を図ることができます。

こちらもサンプルアプリを組み込んでみました。

通常のスタイリング SCSSを利用したスタイリング
通常スタイリング
SCSSスタイリング

このアプリではモーダルの中のコンポーネントではスタイリングのオブジェクトのキー名を統一しています。(styles.hogehogehogehogeにあたる部分)

よってソース的な差分はスタイル部分のみとなります。

通常スタイルの記法とSCSSを利用した記法両方において同一のスタイリングが可能であることがわかりますね。

また、共通化している部分としてはこちらのファイルに記載されている内容で、テキスト周りやコンテナの大枠のスタイリングを決めています。

導入方法

最後に導入方法を記載いたします。

基本的には公式ドキュメントに記載されている方法で完結します。

github.com

手順

1. インストールコマンドを叩く

yarn add --dev react-native-sass-transformer sass

2. metro.config.jsの記述を変更する。 今回私が作成したサンプルアプリでは下記のような内容になります。

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/