React Native

React Native (Expo)とReact Navigationで画面遷移を実装する

Katz

はじめに

React Native (Expo)では画面遷移を実装するにはReact NavigationかExpo Routerを利用する方法が一般的らしい。今回はReact Navigationを利用した画面遷移の方法について調べたのでまとめる。

React Navigationとは?

  • React NativeにはWebページの遷移のような、新しいページに遷移したら古いページに戻るような、ページ履歴を管理するような仕組みを用意していない。
  • このようなWebページの遷移、ページ履歴の管理する機能を提供するのがReact Navigationです。React Nativigationを利用すると複数の画面間での画面遷移を実装できる。

実装方法

実装方法としてStatic configurationとDynamic configurationがあるらしい。

名称詳細
Static configuration必要な定型文、Type Scriptの型、ディープリンクなどを簡素化したもの
Dynamic configurationStatic configurationと比べると柔軟な設定変更に対応しているが、定型文やディープリンクの実装が必要になる。

React Navigationを初めて使う人はStatic configurationの方がおすすめらしいので今回はStatic configurationを利用する。

プロジェクト作成

React NativeのExpoプロジェクトを普通に作成すると、Expo Routerがインストールされてしまうので、以下のコマンドを利用して空のプロジェクトを作成する。

npx create-expo-app Project-Name --template blank-typescript

インストール

React Navigationを利用するにあたり以下のパッケージをインストールする。

名称詳細
@react-navigation/nativeReact NavigationのパッケージでReact NativeでReact Navigationを利用する時に使う
@react-navigation/native-stackReact NavigationのパッケージでReact Nativeで画面スタックを利用する時に使う
@react-navigation/elementsReact Navigationのパッケージで画面遷移で利用するヘッダーなどのコンポーネントが定義されている。また画面遷移で利用するヘルパー関数などが定義されている。
@react-native-screensreact-navigation/native-stackが依存しているパッケージ
@react-native-safe-area-contextReact NativeでSafeAreaの取り扱いを楽にするパッケージ
npm install @react-navigation/native @react-navigation/native-stack @react-navigation/elements
npx expo install react-native-screens react-native-safe-area-context

画面遷移を実装する

Navigation

  • HomeとDetailsの2つの画面を作成するのでscreensに登録する
  • Homeは初期表示の画面とするのでinitialRouteNameに登録する
  • TypeScriptを利用する場合には型周りで警告が出てしまうので、StaticParamListを利用してRootStackParamListを作成する。
const RootStack = createNativeStackNavigator({
  initialRouteName: 'Home',
  screens: {
    Home: HomeScreen,
    Details: DetailsScreen,
  },
});

const Navigation = createStaticNavigation(RootStack);

type RootStackParamList = StaticParamList<typeof RootStack>;

HomeScreen

  • useNavigationでNavigationを取得して、Navigationを利用して画面遷移する
  • navigateを呼び出すと、指定した画面に遷移することができる。
function HomeScreen() {
  const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
  return (
      <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
          <NavigationButton onPress={() => navigation.navigate('Details')} text="Go to Details" />
      </View>
  );
}

type NavigationButtonProps = {
  onPress: () => void;
  text: string;
}

function NavigationButton({ onPress, text }: NavigationButtonProps) {
  return (
    <View style={{ width: '100%', paddingHorizontal: 10 }}>
      <Button 
        onPress={onPress} 
        style={{ width: '100%', padding: 10, alignItems: 'center' }}
      >
        {text}
      </Button>
    </View>
  );
}

DetailsScreen

  • useNavigationでNavigationを取得して、Navigationを利用して画面遷移する
  • pushを呼び出すと、遷移先の画面が既に表示されている場合にでも、画面に遷移することができる。(navigateでは既に表示されている場合は画面遷移できない)
  • goBackを呼び出すと、一番上にスタックされている画面を削除して、1つ前に表示されていた画面に戻ることができる。
  • popToを呼び出すと、複数のスタックした画面を削除して、指定した画面まで戻ることができる。
  • popToTopを呼び出すと、一番下にスタックされている画面以外は削除して、一番したに表示されている画面に戻ることができる。
function DetailsScreen() {
  const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
  return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', gap: 10, width: '100%' }}>
        <NavigationButton onPress={() => navigation.push('Details')} text="Go to Details" />
        <NavigationButton onPress={() => navigation.goBack()} text="Go back" />
        <NavigationButton onPress={() => navigation.popTo('Home')} text="Go to Home" />
        <NavigationButton onPress={() => navigation.popToTop()} text="Go back to first screen in stack"/>
      </View>
  );
}

type NavigationButtonProps = {
  onPress: () => void;
  text: string;
}

function NavigationButton({ onPress, text }: NavigationButtonProps) {
  return (
    <View style={{ width: '100%', paddingHorizontal: 10 }}>
      <Button 
        onPress={onPress} 
        style={{ width: '100%', padding: 10, alignItems: 'center' }}
      >
        {text}
      </Button>
    </View>
  );
}

動作を確認する

最終的にはこのようなコードが出来上がる。

import * as React from 'react';
import {View, Text, Pressable} from 'react-native';
import {createStaticNavigation, StaticParamList, useNavigation} from '@react-navigation/native';
import { createNativeStackNavigator, NativeStackNavigationProp } from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';

const RootStack = createNativeStackNavigator({
  initialRouteName: 'Home',
  screens: {
    Home: HomeScreen,
    Details: DetailsScreen,
  },
});

const Navigation = createStaticNavigation(RootStack);

type RootStackParamList = StaticParamList<typeof RootStack>;

function HomeScreen() {
  const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
  return (
      <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
          <NavigationButton onPress={() => navigation.navigate('Details')} text="Go to Details" />
      </View>
  );
}

function DetailsScreen() {
  const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
  return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', gap: 10, width: '100%' }}>
        <NavigationButton onPress={() => navigation.push('Details')} text="Go to Details" />
        <NavigationButton onPress={() => navigation.goBack()} text="Go back" />
        <NavigationButton onPress={() => navigation.popTo('Home')} text="Go to Home" />
        <NavigationButton onPress={() => navigation.popToTop()} text="Go back to first screen in stack"/>
      </View>
  );
}

type NavigationButtonProps = {
  onPress: () => void;
  text: string;
}

function NavigationButton({ onPress, text }: NavigationButtonProps) {
  return (
    <View style={{ width: '100%', paddingHorizontal: 10 }}>
      <Button 
        onPress={onPress} 
        style={{ width: '100%', padding: 10, alignItems: 'center' }}
      >
        {text}
      </Button>
    </View>
  );
}

export default function App() {
  return <Navigation />;
}

上記のコードを実行すると以下のような動作になる。

まとめ

  • React Navigationを利用するとReact Native (Expo)プロジェクトでも画面遷移が実装できる。
  • React Navigationを利用すると複数画面による画面遷移をnavigate・goBack・popTo・popToTopなどで制御できる。

参考文献

ABOUT ME
Katz(Yusuke Katsuragawa)
Katz(Yusuke Katsuragawa)
Androidエンジニア
AndroidエンジニアをやっているKatzです。最近はKotlin Multiplatformを中心にやっています。経歴やお仕事の依頼については、私のプロフィールに詳細を記載していますので、ご確認ください。
記事URLをコピーしました