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のスタイルで戸惑うことは少なくなるでしょう。
