Development • December 11, 2025 • 30 minutes read • Kadi Kraman • Engineering
すべてのWeb開発者が最初のReact Nativeアプリを作るために知っておくべきこと。
React Nativeは、Reactの経験があるWeb開発者が最初のモバイルアプリを作るのに非常に適した選択肢です。ReactとReact Nativeは多くの類似点がありますが、Webとネイティブをターゲットにする場合には重要な違いも存在します。本記事は、ReactからReact Nativeへ移行する際に開発者がよく犯すミスやよくある疑問点を取り上げ、解説することを目的としています。新しいプラットフォームに踏み出す際の「知らなかった未知」を少しでも明確にし、Webからネイティブへの移行を楽にする手助けになれば幸いです。
なぜReact Nativeを選ぶのか
React開発者がReact Nativeを選ぶべき理由をいくつか挙げます。
- スキルの移転が容易
- React Nativeでは、アプリケーションコードのほとんどがJavaScript(多くはTypeScript)で書かれます。つまり、経験のあるReact開発者はWebで慣れているコーディングパターンやライブラリの多くを引き続き使えます。
- 本当にネイティブ
- ほとんどのアプリコードをJavaScriptで書くとはいえ、React Nativeアプリは内部では本物のネイティブアプリです。あなたが書いたReactコードは各プラットフォームの実際のネイティブプリミティブにマッピングされます。これはパフォーマンスとネイティブらしさにとって非常に重要です。
- マルチプラットフォームでのコード共有
- React Nativeは同じコードベースからiOSとAndroidの両方のネイティブアプリを構築できます。Expo RouterやAPI Routersを使えば、さらにWebやサーバーもターゲットにできます。つまり、プラットフォーム間で大量のコードを共有できる可能性があります。
なぜExpoを選ぶのか
ExpoはReact Nativeフレームワークです — Next.jsがReactフレームワークであるのと似ています。
React Native自体はネイティブiOS/Android上でReactコードを動かすための基礎を提供します。Text、View、TextInputのような基本コンポーネントも含まれています。しかし、ナビゲーション、プッシュ通知、カメラ利用、アプリ起動間のデータ永続化、ストア向けビルドといった、ほとんどのプロダクションアプリが必要とする多くの機能はReact Nativeコアには含まれていません。これは意図的な設計で、すべてのネイティブ機能を最初から露出すると、Metaの小さなReactチームではReact Nativeを維持できなくなるためです。
コアに主要な機能が含まれないため、開発者は常にさまざまなコミュニティライブラリに頼ってきました。リリースからほぼ10年経ち、選択肢は膨大になっています。特に新規プロジェクトの立ち上げ時には、どのライブラリを選び、どれが相互にうまく動くかを判断するのが難しいことがあります。理想的には、よく使われ、よく保守されたツール群がセットになっていて、開発者が毎回選択に悩まなくて済むのが望ましいです。これがまさにExpoが助ける点です。
ExpoはReact Nativeフレームワークであり、React Nativeが提供するものとプロダクションアプリに必要なその他すべての間のギャップを埋めるツールとサービスの集合です。Expo SDKはReact Native用の拡張標準ライブラリであり、コアに含まれない一般的なネイティブAPI(カメラ、ビデオ、通知など)へのアクセスを提供します。Expoは新しいプロジェクトを作成するためのCLI、学習とプロトタイピング用のサンドボックスアプリ、ファイルシステムベースのナビゲーションシステム、ネイティブコードを管理するツール、アプリをストアにビルド・配信する仕組み、OTA(オーバーザエア)アップデートのセットアップ、さらには独自のネイティブモジュールをビルドするための仕組みを提供します。これらに加えて、ほとんどのオープンソースのReact NativeライブラリもExpo SDKと併用できます。
Metaも新規作成アプリに対してExpoのようなReact Nativeフレームワークの使用を公式に推奨しています。その理由は単純です: フレームワークを使うか、あるいは自分でフレームワークを作るかのどちらかであり、自分でフレームワークを作るのは大多数のReact Native開発者にとって賢明な選択ではないからです。
React Native keynote at React Conf 2024
(ここは元記事の見出しとして残します)
ReactとReact NativeのUIプリミティブ
ネイティブのReact NativeコードはReactのコードと見た目が似ていますが、レンダリングの面で明確な違いがあります。以下はWebでのテキスト表示の例です。
export function MyTextComponent() {
return (
<div>
Hello, web!
</div>
);
}
同じことをReact Nativeで表示する方法は次の通りです。
import { View, Text } from "react-native";
export function MyTextComponent() {
return (
<View>
<Text>Hello, native!</Text>
</View>
);
}
これらの例は、WebのReactとネイティブのReactの非常に重要な違いを示しています: React NativeにはHTMLのプリミティブ(div、input、formなど)が存在しません。代わりに、それらに相当するプリミティブコンポーネントがreact-nativeライブラリからエクスポートされます。したがって、React Nativeでレンダリングするすべてのものは常にコンポーネントでラップされます。内部的にはReact Nativeはプラットフォームごとの実際のネイティブコンポーネントをレンダリングしますし、そのためUIに表示されるすべてのテキストはTextコンポーネントでラップする必要があります。これを怠るとアプリがクラッシュします。
以下はReact Nativeに含まれる主なUIプリミティブの一部です。
-
View
- Webでの最も近い相当: div
- ViewはWebのdivに相当し、レイアウトとスタイリングに使用されます。
-
ScrollView
- Webでの最も近い相当: div
- Webではページはデフォルトでスクロール可能ですが、ネイティブではそうではありません。ページをスクロール可能にするにはScrollView(またはFlatListやSectionListのような仮想化されたリスト)でラップする必要があります。
-
Text
- Webでの最も近い相当: p
- React NativeでレンダリングするすべてのテキストはTextでラップする必要があります。
-
Image
-
Webでの最も近い相当: img
-
画像コンポーネントはURLからもローカルファイルからも画像をレンダリングできます。APIはWebと少し異なります。例えばURLから画像を読み込むには次のようにします。
import { Image } from "react-native";
export function MyImage() {
return <Image source={{ uri: "https://domain.com/static/my-image.png" }} />;
}
-
ローカルファイルからレンダリングするには次のようになります。
import { Image } from "react-native";
const imageSource = require("../assets/my-image.png");
export function MyImage() {
return <Image source={imageSource} />;
}
-
多くのプロダクションアプリは組み込みのImageコンポーネントではなく、FastImageやExpo Imageを使います。これらのライブラリはスタイリング、キャッシング、追加の画像フォーマット対応などの機能を含んでいます。
-
FlatList
-
Webでの最も近い相当: array.map()
-
Webでは配列をmapして長いリストをレンダリングすることが多いですが、ネイティブではパフォーマンス上の理由から避けるべきです。代わりにFlatListを使いましょう。FlatListは仮想化されたリストで、不要なデータのレンダリングを遅延させる、基になるデータが変わらない限りリストを再レンダリングしないなどの最適化が組み込まれています。
import { Text, FlatList, View } from "react-native";
const posts = [
{ id: "1", name: "Post 1" },
{ id: "2", name: "Post 2" },
];
export function MyList() {
return (
<FlatList
data={posts}
renderItem={({ item }) => (
<Text>{item.name}</Text>
)}
/>
);
}
-
TextInput
-
Webでの最も近い相当: <input type="text" />
-
テキスト入力コンポーネントはテキストベースの入力全般に使います。Webのinputと異なり、テキスト(および数値)用に設計されています。TextInputにはonChangeコールバックもありますが、通常は更新されたテキスト文字列を直接返すonChangeTextを使います。
import { useState } from "react";
import { StyleSheet, TextInput } from "react-native";
export function MyInput() {
const [value, setValue] = useState();
return <TextInput value={value} onChangeText={setValue} />;
}
-
TouchableOpacity
-
Webでの最も近い相当: button
-
タップに反応する領域を作りたいときは、その領域をTouchableOpacityでラップします。名前の通り、押されたときに自動的にハイライトされ、activeOpacityプロップで強調の度合いを調整できます。
import { TouchableOpacity, Text } from "react-native";
export function MyButton() {
const onPress = () => {
console.log("Pressed!");
};
return (
<TouchableOpacity onPress={onPress} activeOpacity={0.8}>
<Text>Button Text</Text>
</TouchableOpacity>
);
}
-
Pressable
- Webでの相当: <button />
- TouchableOpacityに似ていますが、Pressableはタッチアクションに対してより高いレベルの制御を提供する後継コンポーネントです。
-
Switch
-
Webでの相当: <input type="checkbox" />
-
Switchは値をtrue/falseで切り替えるトグルコンポーネントです。iOSとAndroidで見た目が異なるプラットフォーム固有の実装の好例です。
import { Switch } from "react-native";
export function MySwitch() {
const [value, setValue] = useState(false);
return (
<Switch
value={value}
onValueChange={(value) => setValue(value)}
trackColor={{ true: "pink" }}
/>
);
}
上記はReact Nativeのコアコンポーネントの抜粋です。完全な一覧や詳細は公式のReact Native docsを参照してください。
React Nativeのスタイリング
WebでのCSSの書き方を知っていれば、React Nativeのスタイリングは比較的簡単に学べます。多くのCSSプロパティがサポートされていますが、いくつか違いがあります。
グローバルスタイルはない
すべてのスタイルはインラインでコンポーネントにstyleプロップとして渡されます。スタイリングライブラリを使わない限り、グローバルスタイルを定義することはできません。コンポーネント間でスタイルを共有するには、例えばテーマファイルを作成して各ファイルでインポートするといった方法があります。
import { View, Text } from "react-native";
export function MyComponent() {
return (
<View style={styles.container}>
<Text style={styles.greeting}>Set Reminder</Text>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: "#fff", padding: 24 },
greeting: { fontSize: 24 },
});
Flexbox — 少しの違いあり
React Nativeでは配置にFlexboxを使います。Webと近い挙動ですが、いくつかの違いがあります:
- すべての要素はデフォルトで display: flex
- flexDirection のデフォルトは column(Webは row)
- alignContent のデフォルトは flex-start(Webは stretch)
- flexShrink のデフォルトは 0(Webは 1)
- flexプロパティは単一の数値のみサポート
スタイリングライブラリ
組み込みのインラインスタイルは十分な場合が多いですが、代替のスタイリング体験を望む開発者向けのライブラリもあります。人気のあるライブラリには次のようなものがあります:
- NativeWind — React NativeでのTailwindスタイル
- Unistyles — より包括的なStyleSheet
- Styled Components — CSS構文でスタイル記述
- Tamagui — クロスプラットフォームのスタイリングとUIキット
もしさらに深掘りしたければ、以前に実施したLiveStream(さまざまなアプローチを比較したもの)をチェックしてください。