React Nativeの基本的なモジュール(1)
それでは、React NativeやExpoでアプリ開発をする際に、頻出するモジュールを見ていきましょう。これらのモジュールは、React Nativeの標準ライブラリとして提供されており、Expoを使っている場合でもfrom "react-native"
として直接インポートすることになります。公式ドキュメントでの表現に沿う形で、Reactコンポーネントとして提供されるモジュールのことは「コンポーネント」、それ以外のモジュールのことは「API」と呼ぶことにします。
Viewコンポーネント
まず、最も基本となるのがView
コンポーネントです。これは、HTMLのdiv
要素に近い使い方をするもので、任意の階層でネストしてUIのレイアウトを構築するためのコンポーネントです。単独では何も表示されないので、サンプルでは少し色付けしたView
コンポーネントを配置してみましょう(リスト2)。
import { StatusBar } from 'expo-status-bar'; import { StyleSheet, View } from 'react-native'; export default function App() { return ( <View style={styles.container}> {/* (1) 長さ100四方の赤い領域を作る */} <View style={{ width: 100, height: 100, backgroundColor: 'red' }} /> <StatusBar style="auto" /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, });
(1)で、インライン方式のスタイルにより、width
とheight
に100を指定し、backgroundColor
にred
を指定しています。これにより、長さ100四方の赤い領域が表示されます(図2)。
ちなみに、基本的に長さの単位はピクセルで指定しません。これは、AndroidとiOSがそれぞれ画面の解像度にかかわらず、同じサイズのUIを表示するための仕組みを持っているためです。Androidは1dp
、iOSは1pt
という長さの単位を持っており、これらはそれぞれ画面の解像度に応じて適切なピクセル数に変換されます。React Native上では、単位なしの数値として指定し、実際に描画する際にはdp
やpt
に変換されるものと覚えておいてください。
ブラウザでの開発に慣れている方向けに、div
要素と異なる点をいくつか挙げておきます。まず、 View
コンポーネントは、デフォルトでdisplay: 'flex'
が適用されているため、Flexboxの各種プロパティを使ってレイアウトを構築することができます。そして、スマートフォンが縦長であることから、デフォルトでflexDirection: 'column'
が指定されているので、何も指定しない場合は子要素が縦方向に並びます。
また、View
コンポーネントは、ネイティブUI側の挙動を踏襲する形でoverflow: 'hidden'
相当の挙動をするため、子要素が親要素からはみ出してもスクロールできません。後述するScrollView
コンポーネントを使うことで、スクロール可能な領域を作ることができます。
最後にもうひとつ、div
要素との大きな違いとして、View
コンポーネントの直下にはテキストを記述することができません。style
propsにも、文字列を装飾するためのcolor
やfontSize
などのプロパティはありません。テキストを表示するためには、次項で解説するText
コンポーネントを使う必要があります。
View
で使えるスタイルについては、公式ドキュメントを参照してください。
レイアウトに関するスタイルが網羅されているため、React Nativeのほとんどのコンポーネントは、このスタイルを踏襲しています。CSSの知識があれば、React Nativeのスタイルもすぐに使いこなせることでしょう。
Textコンポーネント
前述の通り、View
コンポーネントにはテキストを記述することができません。これは、モバイルアプリの世界ではテキストがブラウザほど優遇されるものではないからです。ブラウザは元々、学術論文などを表示するためのドキュメントビューアとしてスタートしているため、テキストがメインコンテンツであり、最も重要なものでした。
一方、モバイルアプリにとっては、テキストは画像や動画などのメディアと同じくらいの重要度であり、そこまで特別扱いするものではありません。そのため、AndroidでもiOSでも、テキストを表示するためのUIコンポーネントが特別に用意されました。
ネイティブなUIコンポーネントを可能な限り尊重するReact Nativeでは、これらの世界観を踏襲し、テキストを表示するためにはText
コンポーネントを使うことになっています。リスト3のように使います。
import { StyleSheet, Text, View } from 'react-native'; // (省略) export default function App() { return ( <View style={styles.container}> {/* (1) テキストを表示する */} <Text>Hello world!</Text> {/* (2) ネストして表示する */} <Text style={{ fontWeight: 'bold' }}> Textをネストさせることで <Text style={{ color: 'red' }}>インラインスタイル</Text> を適用できます </Text> <StatusBar style="auto" /> </View> ); } // (省略)
(1)では、最も素直な使い方として、JSXの子要素に文字列を指定しています。(2)では、Text
コンポーネントをネストして、一部分にだけ別のスタイルを適用しています。実際に表示してみると、図3のようになります。
(2)に相当する表示を見てみると、全体としては太字になりつつ、一部分だけ赤くなっていることがわかります。Web標準の言葉で説明するなら、外側のText
コンポーネントはブロックレベルコンテンツ、内側のText
コンポーネントはインラインレベルコンテンツに相当します。このように、Text
コンポーネントは、ブロックとインラインのそれぞれの振る舞いを使い分けながら、文章表現を行うためのコンポーネントです。
style
propsで使えるプロパティも、テキストの装飾に特化したものが多いです。例えば、 color
やfontSize
などがあります。Text
コンポーネントのスタイルについての詳細は、公式ドキュメントを参照してください。
UIライブラリでも、多くのコンポーネントはView
とText
の組み合わせでできているため、これらのコンポーネントを使いこなすことができれば、React NativeのUIライブラリを使う際にも、裏側で何が動いているのかあたりをつけやすくなるでしょう。
Imageコンポーネント
次はImage
コンポーネントです。これは文字通り画像を表示するためのコンポーネントで、ブラウザでいうimg
要素に相当します。リスト4のように使います。
import { Image, StyleSheet, View } from 'react-native'; // (省略) export default function App() { return ( <View style={styles.container}> {/* (1) インターネット上の画像を表示する */} <Image source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }} style={{ width: 64, height: 64 }} /> {/* (2) アプリ内の画像を表示する */} <Image source={require('./assets/favicon.png')} style={{ width: 48, height: 48 }} /> <StatusBar style="auto" /> </View> ); } // (省略)
基本的な使い方は、画像の取得元をsource
propsに指定すること、そして画像のサイズを指定することです。
source
の指定の方法は大別すると2つあります。ひとつは(1)のように、オブジェクトを渡してuri
プロパティにURLを指定する方法です。この方法を使用する場合は、必ず画像のサイズを併記する必要があります。併記しない場合、サイズがゼロと見なされて、何も表示されないことがあります。
もうひとつは(2)のように、require
関数を使って、アプリ内の画像ファイルを指定する方法です。この方法を使用する場合は、画像のサイズを併記しなくても、画像ファイルのサイズが自動的に使われます。実際に表示してみると、図4のようになります。
もし手元で試している場合は、style
propsで指定しているサイズを削除してみると、画像が表示されないことがわかると思います。
Image
コンポーネントにも、専用のスタイルがあります。例えば、resizeMode
propsを使うことで、画像のリサイズ方法を指定することができます(リスト5)。
// (省略) <Image source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }} style={{ width: 64, height: 30, // 少し潰れた領域に表示する // (1) 画像の縦横比は保ちつつ、上下や左右が切れてもいいので長編に合わせる resizeMode: 'cover', }} /> // (省略)
これは実際に見たほうがわかりやすいので、実行例を見てみましょう(図5)。
画像自体は縦横比を保って潰れたり歪んだりさせず、widthとheightで指定した領域で切り取るように表示されます。これ以外にも、画像を小さく表示するcontain
や、画像を歪めてでも領域内にピッタリ合わせる stretch
など、さまざまなリサイズ方法が用意されています。詳しくは公式ドキュメントを参照してください。
コンポーネントに専用のスタイル形式が用意されているのは、View
とText
と Image
だけです。他のすべてのコンポーネントについているstyle
propsは、これらのいずれかのスタイルを踏襲しているので、この3つの挙動を理解すれば、React Nativeのスタイルで戸惑うことは少なくなるでしょう。