React Navigation でマルチページルーティングを実装
ウェブ開発では、URLバーの変更(例: /home や /profile)でページを切り替えるのが一般的です。しかし、スマホアプリにはURLバーが存在しません。
ナビゲーションライブラリ(Navigation Library)に依存して画面階層を管理する必要があります。React Nativeエコシステムでは、最も権威があり市場シェアの高いソリューションが React Navigation です。最新のExpo RouterはこれをNext.jsとほぼ同じ「ファイルベースルーティング(File-based Routing)」に進化させました!
1. Expo Routerとは?
以前のRNを書いたことがある方なら、Stack.Navigator や Stack.Screen を大量に書く恐怖を覚えているでしょう。
最新版のExpoでは Expo Router が導入されました。これはNext.jsのApp Routerコンセプトを直接借用したものです:フォルダ内に作成したファイルが自動的にページになります!
フォルダ構造は次のようになります:
app/
├── _layout.tsx # グローバルレイアウト設定
├── index.tsx # ホームページ(デフォルトで開く)
├── profile.tsx # プロファイルページ
└── settings.tsx # 設定ページ
2. Stack Navigation:スタック型ナビゲーション
スマホアプリで最も一般的なナビゲーション方法が「スタック(Stack)」です。
トランプの山を想像してください。商品をクリックして詳細ページに入るのは、新しいカードを一番上に置くようなものです。左上の < 戻る をクリックすると、一番上のカードを取り除いて前のページに戻ります。
app/_layout.tsx でStackレイアウトを定義します:
import { Stack } from 'expo-router';
export default function RootLayout() {
return (
<Stack>
{/* 異なるページごとにヘッダーをカスタマイズ */}
<Stack.Screen
name="index"
options={{ title: 'ホーム', headerShown: false }}
/>
<Stack.Screen
name="profile"
options={{ title: 'プロファイル', presentation: 'modal' }}
/>
<Stack.Screen
name="settings"
options={{ title: 'システム設定' }}
/>
</Stack>
);
}
[!TIP]
presentation: 'modal'オプションに注目してください。iOSでは、この設定を追加すると新しいページが「下から上」にスライドして表示されます(デフォルトの右から左ではなく)。これがクラシックなネイティブインタラクション体験です!
3. ページ間の移動(Linkとrouter)
ページができたら、どうやって移動するのでしょうか?Next.jsと非常に似ており、2つの方法があります:
方法1:<Link> コンポーネントを使用(ボタン/テキストに適している)
import { Link } from 'expo-router';
import { View, Text } from 'react-native';
export default function Home() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>ホームへようこそ</Text>
{/* asChildはクリックイベントを内部のTouchableOpacityにバインド */}
<Link href="/profile" asChild>
<TouchableOpacity style={{ marginTop: 20, padding: 10, backgroundColor: 'blue' }}>
<Text style={{ color: 'white' }}>プロファイルへ移動</Text>
</TouchableOpacity>
</Link>
</View>
);
}
方法2:router APIを使用(関数ロジック内で適している)
import { router } from 'expo-router';
function handleLoginSuccess() {
// 認証成功後、プログラムで強制移動
router.push('/dashboard');
// または、ユーザーが戻るボタンでログインページに戻れないようにする場合はreplaceを使用
// router.replace('/dashboard');
}
4. 実践:IGスタイルのBottom Tabs(底部ナビゲーションバー)を作成
現在、ほぼすべての主流アプリ(Instagram、Line、Spotifyなど)が底部ナビゲーションバーを使用しています。 Expo Routerでこの機能を実装するのは超簡単です!
まず、Tabs専用のフォルダ構造を作成します:
app/
├── _layout.tsx # ルートのStack(ログインページなどTabのない画面用)
└── (tabs)/ # 括弧はルートグループを示し、URLに表示されない
├── _layout.tsx # Bottom Tabsの見た目を定義
├── index.tsx # ホームTab
└── explore.tsx # 探索Tab
app/(tabs)/_layout.tsx を設定します:
import { Tabs } from 'expo-router';
import { Home, Search } from 'lucide-react-native'; // アイコンライブラリをインストール
export default function TabLayout() {
return (
<Tabs screenOptions={{
tabBarActiveTintColor: '#3b82f6', // 選択時の色
headerShown: true // ヘッダーを表示するか
}}>
<Tabs.Screen
name="index"
options={{
title: 'ホーム',
tabBarIcon: ({ color }) => <Home color={color} size={24} />,
}}
/>
<Tabs.Screen
name="explore"
options={{
title: '探索',
tabBarIcon: ({ color }) => <Search color={color} size={24} />,
}}
/>
</Tabs>
);
}
たったこれだけのコードで!iOS/Androidのネイティブデザインガイドラインに完全準拠し、スムースなスライドアニメーションと触覚フィードバックを備えた底部ナビゲーションバーが完成します!
5. パラメータの受け渡し(Route Parameters)
「記事一覧」で記事をクリックして「記事詳細ページ」に移動する場合、記事IDを渡す必要があります。
パラメータを送信:
// 一覧ページで
router.push({ pathname: '/post/[id]', params: { id: 123, title: 'こんにちは' } });
パラメータを受信:
ファイル名が app/post/[id].tsx の場合:
import { useLocalSearchParams } from 'expo-router';
import { View, Text } from 'react-native';
export default function PostDetail() {
// 渡されたパラメータを分解
const { id, title } = useLocalSearchParams();
return (
<View>
<Text>現在表示中の記事ID: {id}</Text>
<Text>記事タイトル: {title}</Text>
</View>
);
}
ナビゲーションシステムをマスターすれば、アプリに完全な骨格が備わります。次章では、スマホアプリだけが可能な領域に進みます:カメラの呼び出し、GPS位置情報の取得、プッシュ通知の送信!