⚡️

【React Native】Expo Routerを導入する

に公開

概要

今回は、React Native に Expo Router を導入して基本的なルーティングを構築して動作確認しました。あわせて BottomTab ナビゲーションと併用する方法も検証してみました。

Expo Router とは?

React NativeとWebアプリケーションのためのファイルベースのルーティングライブラリ

Next.js みたいな使い方ができる様です 👀

https://docs.expo.dev/versions/latest/sdk/router/

動作環境構築

早速試していく環境を作成します。 react-native-example ディレクトリを作成し blank-typescript のテンプレートを用いてプロジェクトを作成します。

$ mkdir react-native-example
$ cd react-native-example
$ npx create-expo-app@latest --template blank-typescript

この時点での package.jsondependencies は以下になりました。

  "dependencies": {
    "expo": "~52.0.41",
    "expo-status-bar": "~2.0.1",
    "react": "18.3.1",
    "react-native": "0.76.7"
  },
  "devDependencies": {
    "@babel/core": "^7.25.2",
    "@types/react": "~18.3.12",
    "typescript": "^5.3.3"
  },

インストール

https://docs.expo.dev/router/installation/

👆のドキュメントの Manual installation 前提で進めていきます。

npx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants

複数パッケージを一気にインストールするみたいなので、1個ずつ調べてみたいと思います。

  • expo-router
    • 今回試すパッケージ
  • react-native-safe-area-context
    • デバイスのSafe Area Inset にアクセスするための柔軟なAPIを提供
    • ノッチ、ステータスバー、ホームインジケータ、その他のデバイスやオペレーティングシステムのインターフェイス要素の周囲にコンテンツを適切に配置することができる
    • SafeAreaView コンポーネントも提供しており、View の代わりに使用することで、セーフエリアを考慮したビューを自動的に挿入することができる
  • react-native-screens
    • 通常 ReactNative の画面遷移は JavaScript 上で管理されるが、react-native-screens を導入することで、iOS の UINavigationController や Android の Fragment など、各プラットフォームのネイティブな画面管理を利用できる
    • これにより、画面遷移がよりスムーズになり、メモリ使用量も最適化される
  • expo-linking
    • ディープリンクを簡単に扱える様にする
  • expo-constants
    • アプリに関するさまざまな定数情報(アプリ名、バージョン、ビルド番号、デバイス情報など)を取得できる

👆でインストールされたパッケージは以下になります。

  "dependencies": {
    ...
    "expo-router": "~4.0.20",
    "react-native-safe-area-context": "4.12.0",
    "react-native-screens": "~4.4.0",
    "expo-constants": "~17.0.8",
    "expo-linking": "~7.0.5"
  },

次に package.jsonmain を以下に変更します。

{
  "main": "expo-router/entry"
}

次に app.json または app.config.js に以下を追加します。

{
  "expo": {
    "scheme": "your-app-scheme",
    "plugins": ["expo-router"]
  }
}

これで準備完了です。

ルートページ表示

ちゃんと設定できているか、ルートページだけ設定して表示させてみたいと思います。

まず既存の App.tsx を削除し、新たに app ディレクトリを作成し中に index.tsx を以下内容で作成します。

import { Text } from 'react-native';

const Page = () => {
  return <Text>Page</Text>;
};

export default Page;

これで npm run start でアプリを起動し Page が表示されとけばOKです。

BottomTab と併用する

最後に Bottom Tabs を使う場合はどうなるのか試してみたいと思います。

以下公式ドキュメントを参考に進めていきたいと思います。

https://docs.expo.dev/router/advanced/tabs/

まずは app/_layout.tsx を以下内容で作成します。

import { Stack } from 'expo-router/stack';

const Layout = () => {
  return (
    <Stack>
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
    </Stack>
  );
};

export default Layout;

StackStack.Screen を用いて起動されたら子ルート (tabs) をStackに追加し、 (tabs) 配下が表示されます。StackはAndroid では FragmentActivity+Fragment、iOS では UINavigationController+UIViewController に置き換わる様です。

次に (tabs) ディレクトリを作成し app/(tabs)/_layout.tsx を以下内容で作成します。

import FontAwesome from '@expo/vector-icons/FontAwesome';
import { Tabs } from 'expo-router';

const TabLayout = () => {
  return (
    <Tabs screenOptions={{ tabBarActiveTintColor: 'blue' }}>
      <Tabs.Screen
        name="index"
        options={{
          title: 'Home',
          tabBarIcon: ({ color }) => (
            <FontAwesome size={28} name="home" color={color} />
          ),
        }}
      />
      <Tabs.Screen
        name="settings"
        options={{
          title: 'Settings',
          tabBarIcon: ({ color }) => (
            <FontAwesome size={28} name="cog" color={color} />
          ),
        }}
      />
    </Tabs>
  );
};

export default TabLayout;

最後に各タブの中身を実装していきます。 app/(tabs)/index.tsxapp/(tabs)/settings.tsx を以下内容で作成します。

import { StyleSheet, Text, View } from 'react-native';

const Tab = () => {
  return (
    <View style={styles.container}>
      {/* index.tsxの場合はHome, settings.tsxはSettingsにする*/}
      <Text>Tab [Settings or Home]</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default Tab;

早速動かしてみると👇の様になります。うまく動いてそうです ✨

image1.gif

ちなみに app/_layout.tsxoptions={{ headerShown: false }}true にすると ネイティブのナビゲーションバーが表示されてしまいます 👇。今回はtabが用意しているヘッダーを使うので非表示に設定しています。

image2.gif

参考URL

https://reffect.co.jp/react/expo-router

https://qiita.com/masarufuruya/items/b63a171c1d8fba73cdac

Discussion