【React Native入門】React Navigation(画面移動)の設定方法を理解する

React Nativeを利用してモバイルアプリケーションの開発を行うと必ず画面間の移動が必要になります。React Nativeのみではその機能を持っておらず追加のライブラリのインストールが必要となります。本文書ではReact Navigationを利用して画面間の移動の動作確認を行っています。シンプルなコードのみ利用しているので本文書を通してReact Navigationの設定方法の基本を理解することができます。対象はReact Nativeの学習を開始し始めた人です。
macOSを利用し、Reat Nativeの開発ツールにExpoを利用しReact Navigationのバージョンは7.Xをインストールしています。

ファイルシステムベースルーティングが利用できるExpo Routerを利用することでReact Navigationよりも簡単にナビテーションを設定することができます。特に理由がない限り新しいプロジェクトではこちらを利用するのがおすすめです。
React Nativeの入門書の方であれば先に下記の文書を読んでもらうことをお勧めします。ExpoによるReact Nativeの開発環境の構築には下記の文書の前半に記述しているので参照してください。
動作確認を行なったmacOSのバージョンはsonoma14.5, Xcodeのバージョンは15.3です。
目次
環境を構築する
本文書ではmacOSの環境にNode.jsがインストール済み, XCodeのインストールまたは手元のモバイル機器に”Expo Go”がインストールされている状態から開始しています。
プロジェクトの作成には”npx create-expo-app@latest –template”コマンドを実行します。実行するとテンプレートを選択することができるのでここでは”Blank”を選択しています。またプロジェクト名には任意のreact-native-navigationという名前をつけています。
プロジェクトの作成が完了後、プロジェクトディレクトリに移動して開発サーバを起動するためにnpm startコマンドを実行します。”Expo Go”アプリをiPhoneデバイスにインストールしている場合は表示されいているQRコードをカメラにかざすとExpo Goが起動してアプリ画面が表示されます。iOSのSimulatorを利用する場合はキーボードの”i”を押してください。
下記はiOSのSimulatorですが下記の画面が表示されれば正常に動作しています。

React Navigatorインストールと初期設定についてはReactct Navigatorのドキュメントを参考にして行っていきます。
ライブラリのインストール
React Navigatorの利用するためには1つのライブラリではなく複数のライブラリのインストールが必要になります。最初にreact-navigation/nativeをインストールします。
次に本文書ではExpoを利用しているのでexpoコマンドを利用してreact-native-screens, react-native-safe-area-contextをインストールします。
package.jsonで各ライブラリのバージョンを確認しておきます。
React Navigatorではナビゲーション(画面の移動)する方法として大きく3つ(Stack, Tabs, Drawer)あります。その3つもさらに細かく分けれており5つのライブラリ(Stack, Native Stack, Drawer, Bottom Tabs,Material Top Tabs)に分かれています。どのナビゲーターを利用するかによってインストールするライブラリが異なります。アプリ内で複数のナビゲーションを利用することも可能です。またバージョン7からNavigationの設定方法が2つになり、バージョン7で追加された方法がStatic Configurationと呼ばれ、これまでの方法がDynamic configurationと呼ばれます。これからReact Navigationを使い始める人はStatic Configurationを利用することが推奨されています。

React Navigationのドキュメントに沿っていくとNative Stack Navigatorの設定を解説しているのでまずはNative Stack Navigatorのインストールを行います。
ここまででナビゲーションを実装するために必要なライブラリのインストールが完了したので画面の作成を行います。
プロジェクトフォルダにscreensを作成してHomeScreen.jsを作成します。

App.jsファイルでNavigationを設定します。Navigationの設定にはバージョン7から登場したStaticとこれまでに利用していたDynamicの2つの方法があります。最初はDynamicでの設定を行います。
react-navigation/nativeからimportするNavigationContainerはどのナビデーションでも利用する必須のコンポーネントです。native-stackからimprortしたcreateNativeStackNavigatorを利用してStackを作成し設定を行っています。
Stack.Screenでは作成したコンポーネントのHomeScreenを指定し、name propsで名前をHomeとしています。ここまでの設定でiOS simulatorを確認すると下記のように表示されます。上部のHomeはStack.Screenタグのname propsで指定したHomeです。画面の上部にヘッダーが自動で付与され画面の名前が表示されます。

画面間の移動を行うために新たにscreensフォルダにUserScreen.jsファイルを作成します。
追加したUserScreen.jsファイルをApp.jsファイルに追加します。
ページ間の移動設定を行っていないためUserScreenコンポーネントを追加しても何も変化はありません。
UserScreenコンポーネントを確認したい場合はinitialRouteName prpsをStack.Navigatorコンポーネントで設定することで最初に表示する画面を指定することができます。initialRouteNameをUserに変更することでUser画面が表示されることを確認してください。initialRouteName prpsを設定しないデフォルトの状態では一番上のHomeが表示されることになります。
画面の移動
Home画面からUser画面に移動できるようにHomeScreenコンポーネントにButtonを追加します。
Home画面にはユーザの文字が表示されます。ユーザの文字列をタッチしても変化はありません。

ユーザボタンをタッチするとUser画面に移動できるように設定を行います。設定を行う前にStack.Screenの設定したコンポーネントに渡されるpropsを確認します。
HomeScreenにはpropsでは以下のオブジェクトが渡されます。
コンソールに表示されたpropsの内容を確認するとオブジェクトの中にnavigationとrouteオブジェクトが含まれいていることが確認できます。
2つのオブジェクトの中の1つであるnavigationのnavigate関数を利用します。ButtonにonPressイベントを設定しボタンをタッチするとnavigate関数が実行されます。navigate関数の引数にはStack.Screenのname propsで設定した”User”を指定することができます。
onPressイベントを設定後にユーザボタンをタッチするとUser画面に移動することができます。User画面の上部にはHomeへ戻るためのボタンが表示されておりタッチするとHome画面に戻ることができます。画面を行き来することができるようになります。

ここまでの設定で複数の画面間の移動を実装することができました。
Screenにパラメーターを渡す
HomeScreenコンポーネントに渡されるpropsを再度確認するとnavigationオブジェクトの中にはnavigate以外にもpop, push, goBackなどの関数があることがわかります。またrouteオブジェクトの中にはnameやparamsを確認することができます。

パラメータを渡す場合はnavigate関数で指定したScreenの名前の後にオブジェクトで設定します。
UserScreen.jsでrouteの値をconsole.logでコンソールに出力して確認します。
navigte関数で設定したオブジェクトがparamsの中に入っていることがわかります。route.params.userIdでUserScreenコンポーネントで値を取得することができます。
複数の値を渡したい場合はオブジェクトのプロパティを増やすことで実現できます。
Headerの設定
Screenの上部にはHomeまたはUserといったname propsで設定した値が表示されていました。nameの値の変更はname propsの値を変更することでもできますがoptions propsを利用することで変更が可能です。
設定後User画面を表示するとヘッダーの文字がoptionsのtitleで設定したユーザ画面に変更されることが確認できます。

先ほど確認したパラメータを使ってタイトルを設定することもできます。
optionsの中では関数を利用してtitleを設定することができます。

optionsはrouteだけではなくnavigationのオブジェクトを渡すこともできます。
ヘッダー自体を非表示にしたい場合はoptionsでheaderShownをfalseにすることで実現できます。
ライフサイクルフックの設定
Reactではコンポーネントのマウント時、アンマウント時に何か処理を行いたい場合にuseEffectを利用することができます。画面の移動を行なった時にReactと同様にReact NativeでもuseEffectを利用することができるのか確認していきます。
初期画面のHomeScreen.jsと移動先の画面UserScreen.jsどちらにもuseEffectを設定して動作を確認します。
Home画面を開くと”Home Mount”、その後User画面に移動すると”Home Unmount”が表示され、”User Mount”が表示されると予想できるかと思います。
しかし実際に動作確認を行うと”Home Mount”は表示されますがUser画面に移動しても”Home Unmount”は表示されることはなく”User Mount”が表示されます。Unmountは表示されないものなのではと考えてしまいますがUser画面からHome画面に戻ると”User Unmount”が表示されます。しかし再度”Home Mount”が表示されることはありません。その後はHome画面とUser画面の移動を繰り返しても”User Mount”と”User Unmount”しか表示されることはありません。
理由はReact Navigationの画面の移動にあります。Native Stack Navigatorという名前の通り画面はStackつまり積み重ねによりHome画面からUser画面に移動する際、User画面がHome画面の上に積み重なることで表示されています。Home画面が消えてUser画面が現れるものではありません。そのためUser画面に移動した際はHome画面の上にマウントされHomeに戻る際にはUser画面はアンマウントされます。Homeは一番したの層なので初回表示される際はマウントされますがその後はアンマウントされることはありません。
ここまでの説明でReact Native + React NavigationでのuseEffectの動作が理解できたかと思います。ではHomeScreenでも画面の移動時にある処理を実行したい場合はどのようにすればいいのでしょう?React NativeにはuseFocusEffectというHookが用意されています。useEffectからuseFocusEffectに変更して動作を確認してみましょう。
useFocusEffectはreact-navigation/nativeからimportして利用します。
動作確認を行うとHome画面からUser画面に移動した際には”Home UnFocus”が表示され、User画面からHome画面から戻った時には”Home Focus”が表示されます。
バージョン7から登場したStaticな方法でのNavigationの方法を確認します。
Static NavitagionではcreateNativeStackNavigatorを利用して先にNavigationの設定を記述します。
HomeScreen.jsとUserScreen.jsにはDynamic Navigationで利用したコードを記述します。
iOS simulatorで確認するとホーム画面が表示されます。最初の表示されるページを設定したい場合にはinitialRouteNameを設定することができ、”User”を設定するとUser画面が表示されます。
画面の移動
画面の移動ではuseNavigation Hookを利用することができます。
HomeScreenのpropsを確認してuseNavitagion Hookではなくpropsに含まれるnavitaionオブジェクトが利用されるか確認します。
コードを実行するとpropsに含まれるnavigationオブジェクトがなくなり、routeオブジェクトのみになっていることが確認できます。
Screenにパラメーターを渡す
パラメータを渡す場合はnavigate関数で指定したScreenの名前の後にオブジェクトで設定します。
先ほどHomeScreenコンポーネントのpropsのrouteオブジェクトにparamsが含まれていたのでそこから渡されたパラメータを受け取ることができます。
paramsには渡されたuserId:1が含まれていることが確認できます。
Headerの設定
Headerの設定は下記のように行うことができます。
Native Stack Navigatorの動作確認を行いReact Navigatorライブラリでの画面移動をどのように行うか理解が深まったと思うので次はタブを利用した画面移動の動作確認を行なっていきます。
Tab Navigationを利用するためには別のライブラリreact-navigation/bottom-tabsをインストールする必要があります。
Native Stack NavigatorではNavigationを設定するためにApp.jsでcreateNativeStackNavigatorを利用していましたがTab NavigationではcreateBottomTabNavigatorを利用します。Stack.XXXタグをTab.XXXタグに変更します。
HomeScreen.jsとUserScreen.jsは下記のように記述します。
ライブラリの名前にbottom-tabsとあったようにシュミレーターで確認すると下部(Bottom)にApp.jsで設定したHomeとNameのタブボタンが表示されます。

現在開いている画面のボタンに色がついているのでUserボタンをタッチしてください。タッチするとUser画面が表示されます。
Tabアイコンの変更
デフォルトではタブにアイコンが表示されていますがどちらも同じ形で四角に?が入っているものです。optionsでtaBarIconを設定することでアイコンを変更することができます。
アイコンの設定には@expo/vector-iconsを利用します。Expoではデフォルトから利用することができるため追加のライブラリのインストールは必要ありません。tabBarIconでは関数を利用して設定します。color, sizeが渡されるのでIoniconsではそれらの値を利用してサイズと色を設定しています。
tabBarIconを設定するとHome側のアイコンが変更されていることが確認できます。

User側のアイコンも更新します。
Headerの設定
Native Stack Navigatorの時と同様にoptionsのtitleを利用して画面上部に表示されているヘッダーのタイトルを変更することができます。
titleを設定することでヘッダーのタイトルだけではなくタブボタンのタイトルも変更されることが確認できます。

アイコンの色を設定した場合はscreenOptionsで設定を行うことができます。tabBarActiveTintColorは表示されている画面の色、tabBarInactiveTintColorは表示されていない画面の色です。

画面の移動
Tabs Navigationでは画面下部にあるタブボタンをタッチすることで画面を移動することができました。navigation.navigate関数を利用して追加したボタンをタッチすることで画面を移動することができるのか確認します。パラメーターも一緒に設定を行います。
設定をするとUser画面の移動を行うことができます。User側でrouteオブジェクトからパラメーターを取得して表示することができます。
しかしタブボタンを利用してUser画面に移動しようとするとroute.params.userIdの値は持っていないのでコンソールには”TypeError: undefined is not an object (evaluating ‘route.params.userId’)”が表示されます。
Drawer Navigationを利用したい場合には@react-navigation/drawerライブラリをインストールする必要があります。
そのほかにreact-native-gesture-handler, react-native-reanimatedライブラリのインストールを行います。
babel.config.jsファイルでReanimated Babel Pluginを追加します。
Drawer Navigationの場合はcreateDrawerNavigatorをimportして利用します。
シュミレーターを確認すると画面左上にメニューが表示されます。

メニューをクリックするとDrawer.Screenで設定したnameのHome, Userが表示されます。メニューを非表示にしたい場合は右側に表示されている背景部分をタッチすることでメニューが非表示になります。
メニューをタッチするだけではなく画面左側から右側にフリック(画面左端から右に向けて指をスライドさせる)するとメニューが表示されます。

メニューに表示されている名前をタッチすることで画面の移動を行うことができます。
メニューの名前変更
メニューの名前を変更したい場合はoptionsのtitleを設定することで変更することができます。

Stack NavigatorにはOSが元々持っているナビゲーションを利用したNative Stack NavigatorとJavaScriptを利用してナビゲーションを実装したStack Navigatorがあります。ここではStack Navigatorの設定方法を確認します。Native Stack Navigatorとは異なるライブラリreact-navigation/stackをインストールします。
さらにreact-native-gesture-handlerもインストールする必要があります。
Stack Navigationの場合はcreateStackNavigatorをimportして利用します。またインストールしたreact-native-gesture-handlerもimportします。
NavigationContainerなどの記述はNative Stack Navigatorと同じでNative Stack Navigatorと同様に画面間を移動することができます。
ここまでの動作確認で4つのNavigator(Native Stack, Tabs, Drawer, Stack)の基本設定方法を理解することができました。
Native stack, Tabs, Drawerに関するNavigatorの設定を個別に行なってきましたが一緒に利用することはできるのだろうか?という疑問が湧いてくるかと思います。答えは”Yes”で、Navigatorをネスト化することで同時に利用することができます。ネスト化するというのが最初は難しいかもしれませんが実際にシンプルなコードを使って説明を行うとネスト化の意味が理解できるようになります。
最初にNative Stack Navigatorの中にTabs Navigatorをネスト化した時の動作確認を行います。複数の画面が存在したほうがわかりやすいので新たにFeedScreen.js, MessageScreen.js, SettingScreen.jsの3つのコンポーネントを追加します。
作成する各ファイルの中身はUserScreen.jsを複製し、コンポーネント名とTextタグの中に入れる文字列のみ変更を行います。MessageScreen.jsの場合は下記のようになります。
FeedScreen.js, SettingScree.jsファイルも同じように作成してください。
App.jsファイルでNative Stack Navigatorの設定を行います。Homeに関してはTabs Navigatorのために利用するため区別できるようにファイル名とコンポーネント名をHomeScreenからHomeTabsに変更しています。
HomeTabsコンポーネントの中でTabs Navigaorを設定します。
シュミレーターで表示を確認すると1つの画面上にHomeとFeedのヘッダーが存在し、下部にはHomeTabsで設定したタブが表示されます。HomeTabsによってTabs Navigatorがネスト化されるためにこのような表示になっています。

ヘッダーが2つ表示されている問題がありますが先にNative Stack Navigatorで設定したUser画面を表示させた場合にはどのように表示されるのか確認するためにpropsのinitialRouteNameをUserに設定します。
User画面にタブが表示されることはありません。

Tabs Navigatorで設定されているFeed画面、Message画面では上部にHomeヘッダーを表示させる必要はないのでoptionsのheaderShownをfalseに設定することで非表示にすることができます。
Feed画面からHomeヘッダーを非表示にすることができます。Message画面でも同様にHomeヘッダーが表示されることはありません。

画面の移動
Tabs Navigatorで設定した画面からNative Stack Navigatorで設定した画面に移動を行いたい場合はnavigation.navigate関数を利用することができます。
FeedScreen.jsにボタンを追加しボタンをタッチするとUser画面に移動できるように設定します。
設定するとFeed画面からUser画面に移動することができます。逆にNative Stack NavigatorのUser画面からTabs NavigatorのMessage画面に移動できる確認します。
設定は先ほどFeedScreen.jsファイルで行なったことと同じでnavigation.navigateを利用します。
設定するとUser画面からMessage画面に移動することができます。navigateには”Home”を指定することもできHomeを指定するとFeed画面が表示されます。Homeの後にscreenを設定することでMessage画面に移動することができます。
Native Stack Navigatorの中にDrawer Navigatorをネスト化した時の動作確認を行います。
利用するコンポーネントはNative Stack + Tabs Navigatorで利用したHomeTabs.js, UserScreen.js, SettingScreen.js, FeedScreen.js, MessageScreen.jsとなります。
HomeTabs.jsのファイル名とコンポーネント名をHomeTabsからHomeDrawerに変更します。HomeDrawer.jsではcreateDrawerNavigatorを利用してDrawerの設定を行います。
App.jsでは変更したHomeDrawer.jsをimportします。
シュミレータで確認するとFeedScreen画面が表示され左上にメニューのアイコンが表示されます。

メニューをタッチするとHomeDrawerで設定したFeedとMessageのリンクが表示されます。

FeedScreen画面からNative Stack Navigatorで設定したUser画面の移動はnavigator.navigateで行うことができます。
先ほどはNative Stack Navigatorの中にDrawer Navigatorをネスト化した時の動作確認を行います。今度はその逆でDrawer Navigatorの中にNative Stack Navigatorをネスト化した時の動作を確認します。
App.jsでDrawer Navigatorの設定を行い、HomeStackコンポーネントの中でNative Stack Navigatorの設定を行います。
初期画面にHomeScreenを設定してそこからFeed画面やMessage画面に移動できるようにするためHomeScreenコンポーネントをimportします。Homeという名前はDrawer Navigatorの中で利用しているのでHomeScreenという名前にしています。
HomeScreenコンポーネントからボタンでFeed画面, Message画面に移動できるようにします。
シュミレーターで確認するとヘッダーが2つ表示され、一つはHomeのヘッダーでメニューアイコンが表示されます。もう一つはHomeScreenです。

メニューをタッチするとメニュー画面が表示されます。

User画面に移動するとメニューは表示されたままです。

Home画面からMessage画面に移動するとHomeScreenに戻るためのリンクが表示されます。

戻る際にHomeScreenという文字をBackに変更したい場合はoptionsのheaderBackTitleVisibleをfalseに設定することで実現できます。

このようにDrawer NavigatorにNative Stack Navigatorをネスト化することで画面の移動を行うことができます。
Drawer NavigatorにNative Stack Navigatorをネスト化しましたがさらにTabs NavigatgorをNative Stack Navigatorにネスト化してみましょう。
Drawer Navigatorを設定したApp.jsには変更はありません。
HomeStackコンポーネントにTabs Navigatorを設定するHomeTabsコンポーネントをimportします。先ほどまであったHomeScreenコンポーネントはHomeTabsに移動するため削除しています。
HomeTabs.jsファイルではHomeScreenコンポーネントと新たにNotification.jsファイルを作成してimportしています。Notification.jsの中身はMessageScreen.jsなどを複製して作成しています。
設定が完了したらシュミレータで表示を確認します。ネスト化されているのでヘッダーが3つ表示されます。アイコンを変更したい場合は本文書で説明済みなので”Tabアイコンを変更”を参考に行ってください。

真ん中のHomeTabsが必要ない場合はoptionsのheaderShownをfalseにすることで非表示にすることができます。

このようなNavigatorをネスト化することで複数のNavigatorを同時に利用することができます。