Kosaku Kurino

Kosaku Kurino

【React Native】react-navigation (version3.x)の手ほどき

まえがき

react-nativeアプリを開発していて、react-navigation(version3.x)の基本的な使い方がわかってきたので、このライブラリを利用するにあたり知っておくと助かる情報、使い方をまとめました。react-nativeについての説明はしていないので知らない方は先にreact-nativeを調べて理解してください。抜け等あるかもしれませんので、記載しておいた方がいい内容ありましたら編集リクエスト投げてください。

react-navigationとは

react-navigationは、react-nativeアプリのナビゲーション(ルーティング)履歴を簡単に管理できるライブラリです。ナビゲーション操作ではよく使われるタブバードロワーを簡単に実装できます。

公式サイト(https://reactnavigation.org/)

ナビゲーションの構造を考える

react-navigationナビゲーションを作る際、はじめに構造を考えないといけません。構造と言ってもわからないと思いますので、例を紹介しながら説明しようと思います。

はじめの分岐

はじめてアプリを起動する人にはチュートリアルスクリーンを、2回目以降はホームスクリーンを表示させたいとします。そうすると構造は下記になります。

root(スイッチ)
    - チュートリアルスクリーン
    - ホームスクリーン

スイッチの中に、チュートリアルスクリーンホームスクリーンが同じ階層に並列に存在しているイメージです。

タブでのスクリーン切替

ホームスクリーンでは、タブバーによってホームスクリーンプロフィールスクリーンセッティングスクリーンに切り替えられるようにしたいとします。そうすると構造は下記になります。

root(スイッチ)
    - チュートリアルスクリーン
    - タブ
        - ホームスクリーン
        - プロフィールスクリーン
        - セッティングスクリーン

タブの中に、ホームスクリーンプロフィールスクリーンセッティングスクリーンが同じ階層に並列に存在しているイメージです。

ホームスクリーンとプロフィールスクリーンでのスクリーン遷移

ホームスクリーンでボタンを押すとホーム2スクリーンを表示、プロフィールスクリーンで編集ボタンを押すとプロフィールエディットスクリーンを表示したいとします。そうすると構造は下記になります。

root(スイッチ)
    - チュートリアルスクリーン
    - タブ
        - ホームスタック
            - ホームスクリーン
            - ホーム2スクリーン
        - プロフィールスタック
            - プロフィールスクリーン
            - プロフィールエディットスクリーン
        - セッティングスクリーン

ホームスタックの中に、ホームスクリーンホーム2スクリーンが同じ階層に並列に存在しているイメージです。

ドロワーでのスクリーン切替

タブ内のスクリーンであれば、どこでもドロワーを開けて、ドロワーからタームオブサービススクリーンを表示したいとします。そうすると構造は下記になります。

root(スイッチ)
    - チュートリアルスクリーン
    - ドロワー
        - タブ
            - ホームスタック
                - ホームスクリーン
                - ホーム2スクリーン
            - プロフィールスタック
                - プロフィールスクリーン
                - プロフィールエディットスクリーン
            - セッティングスクリーン
        - タームオブサービススクリーン

ドロワーの中に、タブタームオブサービススクリーンが同じ階層に並列に存在しているイメージです。

まとめ

このように、スイッチスタックタブドロワーを駆使して構造を作って行きます。

また基本的に、同じ階層のナビゲータースクリーン同士しか切替はできません。 なのでホームスクリーンからプロフィールスクリーンに切替したい場合、一度ホームスタックからプロフィールスタックに切替し、プロフィールスクリーンを表示することになります。

react-navigatorには、これらのナビゲーターを簡単に作ることができるcreateSwitchNavigatorcreateStackNavigatorcreateBottomTabNavigatorcreateDrawerNavigatorが用意されています。

上記以外にもcreateMaterialTopTabNavigatorcreateTabNavigator等もあります。

準備

CRNA(create-react-native-app)でアプリケーションを作成します。 次に、react-navigationをインストールします。

npm install create-react-native-app -g
create-react-native-app reactNavigationSample
cd reactNavigationSample
npm install react-navigation --save

ナビゲーションを実装する

構造が決まったので、必要なスクリーンを作成し、react-navigationを利用して、スイッチスタックタブドロワーにぶら下げていきましょう。

root(スイッチ)
    - チュートリアルスクリーン
    - ドロワー
        - タブ
            - ホームスタック
                - ホームスクリーン
                - ホーム2スクリーン
            - プロフィールスタック
                - プロフィールスクリーン
                - プロフィールエディットスクリーン
            - セッティングスクリーン
        - タームオブサービススクリーン

スクリーンの準備

今回必要なスクリーンはチュートリアルスクリーンホームスクリーンホーム2スクリーンプロフィールスクリーンプロフィールエディットスクリーンセッティングスクリーンタームオブサービススクリーンです。

まず、「screens」フォルダを作成し、下記のように適当にスクリーンを作成していってください。

react-nativeの説明は行わないので、スクリプトの説明は省きます。

import React, { Component } from 'react'
import { Platform, StyleSheet, View, Text, Button } from 'react-native'

class HomeScreen extends Component {
  render () {
    return (
      <View>
        <Text>Home</Text>
      </View>
    )
  }
}

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

export default HomeScreen

スタックの作成

ホームスタックプロフィールスタックを作ります。 ホームスタック内ではホームスクリーンとホーム2スクリーンの切替が可能になります。

root(スイッチ)
    - チュートリアルスクリーン
    - ドロワー
        - タブ
            - ホームスタック  // ここ
                - ホームスクリーン
                - ホーム2スクリーン
            - プロフィールスタック  // ここ
                - プロフィールスクリーン
                - プロフィールエディットスクリーン
            - セッティングスクリーン
        - タームオブサービススクリーン

「navigation」フォルダを作成し、AppNavigator.jsを作成しましょう。

import {
  createStackNavigator,
  createBottomTabNavigator,
  createDrawerNavigator,
  createSwitchNavigator
} from 'react-navigation'

import HomeScreen from '../screens/HomeScreen'
import Home2Screen from '../screens/Home2Screen'
import ProfileScreen from '../screens/ProfileScreen'
import ProfileEditScreen from '../screens/ProfileEditScreen'

const HomeStack = createStackNavigator(
  {
    Home: {
      screen: HomeScreen
    },
    Home2: {
      screen: Home2Screen
    },
  },
  {
    initialRouteName: "Home",
  }
)

const ProfileStack = createStackNavigator(
  {
    Profile: {
      screen: ProfileScreen
    },
    ProfileEdit: {
      screen: ProfileEditScreen
    },
  },
  {
    initialRouteName: "Profile",
  }
)

createStackNavigatorを使って、スタックを作成します。

ホームスタックの中には、ホームスクリーンホーム2スクリーンが入るので、Homeをキーに対応するスクリーンをホームスクリーンに、Home2をキーに対応するスクリーンをホーム2スクリーンに設定しています。

initialRouteNameスタック内の初期表示スクリーンを指定できます。

ホームスタックでは、初期表示スクリーンはホームスクリーンに設定しました。

Homeに対応するものはスクリーン以外でも設定でき、スタックにしたりタブにしたりできます。

const HomeStack = createStackNavigator(
  {
    Home: {
      screen: HomeScreen
    },
    Home2: {
      screen: Home2Screen
    },
  },
  {
    initialRouteName: "Home",
  }
)

スタック内でスクリーンの切替を行えるよう修正します。 ホームスクリーンホーム2スクリーンプロフィールスクリーンプロフィールエディットスクリーン を下記のように修正しましょう。

import React, { Component } from 'react'
import { Platform, StyleSheet, View, Text, Button } from 'react-native'

class HomeScreen extends Component {
  render () {
    return (
      <View style={styles.container}>
        <Text>Home</Text>
        <Button
          title="go to Home2"
          onPress={() => this.props.navigation.navigate('Home2')}
        />
      </View>
    )
  }
}

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

export default HomeScreen


this.props.navigation.navigate('スクリーンに対応するキー')でスクリーンの切替ができます。

<Button
  title="go to Home2"
  onPress={() => this.props.navigation.navigate('Home2')}
/>

スタックが完成しました。

root(スイッチ)
    - チュートリアルスクリーン
    - ドロワー
        - タブ
            - ホームスタック(完成)
                - ホームスクリーン(完成)
                - ホーム2スクリーン(完成)
            - プロフィールスタック(完成)
                - プロフィールスクリーン(完成)
                - プロフィールエディットスクリーン(完成)
            - セッティングスクリーン
        - タームオブサービススクリーン

タブの作成

タブを作ります。 タブ内ではホームスタックとプロフィールスタックとセッティングスクリーンの切替が可能になります。

root(スイッチ)
    - チュートリアルスクリーン
    - ドロワー
        - タブ  // ここ
            - ホームスタック(完成)
                - ホームスクリーン(完成)
                - ホーム2スクリーン(完成)
            - プロフィールスタック(完成)
                - プロフィールスクリーン(完成)
                - プロフィールエディットスクリーン(完成)
            - セッティングスクリーン
        - タームオブサービススクリーン

AppNavigator.jsに追記しましょう。

import {
  createStackNavigator,
  createBottomTabNavigator,
  createDrawerNavigator,
  createSwitchNavigator
} from 'react-navigation'

import HomeScreen from '../screens/HomeScreen'
import Home2Screen from '../screens/Home2Screen'
import ProfileScreen from '../screens/ProfileScreen'
import ProfileEditScreen from '../screens/ProfileEditScreen'
import SettingScreen from '../screens/SettingScreen'

const HomeStack = createStackNavigator(
  {
    Home: {
      screen: HomeScreen
    },
    Home2: {
      screen: Home2Screen
    },
  },
  {
    initialRouteName: "Home",
  }
)

const ProfileStack = createStackNavigator(
  {
    Profile: {
      screen: ProfileScreen
    },
    ProfileEdit: {
      screen: ProfileEditScreen
    },
  },
  {
    initialRouteName: "Profile",
  }
)

const Tab = createBottomTabNavigator(
  {
    Home: HomeStack,
    Profile: ProfileStack,
    Setting: {
      screen: SettingScreen,
    },
  }
)

export default Tab

createBottomTabNavigatorを使って、タブを作成します。

タブの中には、ホームスタックプロフィールスタックセッティングスクリーンが入るので、Homeをキーにホームスタックを、Profileをキーにプロフィールスタックを、Settingをキーにセッティングスクリーンを設定しています。

最後にTabexportしておきます。

const Tab = createBottomTabNavigator(
  {
    Home: HomeStack,
    Profile: ProfileStack,
    Setting: {
      screen: SettingScreen,
    },
  }
)

export default Tab

タブが完成しました。

root(スイッチ)
    - チュートリアルスクリーン
    - ドロワー
        - タブ(完成)
            - ホームスタック(完成)
                - ホームスクリーン(完成)
                - ホーム2スクリーン(完成)
            - プロフィールスタック(完成)
                - プロフィールスクリーン(完成)
                - プロフィールエディットスクリーン(完成)
            - セッティングスクリーン(完成)
        - タームオブサービススクリーン

タブの動きの確認

一度動きの確認をします。

App.jsタブを表示させるよう修正します。

import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
import { createAppContainer } from 'react-navigation'
import AppNavigator from './navigation/AppNavigator'

const AppContainer = createAppContainer(AppNavigator)

export default class App extends React.Component {
  render() {
    return <AppContainer />
  }
}

createAppContainerを使って、AppNavigatorをコンテナ化します。

react-navigation(version2.x)では勝手にコンテナ化してくれていたみたいですが、react-native(verison3.x)では手動でコンテナ化してあげないと動きません。

const AppContainer = createAppContainer(AppNavigator)

yarn startexpoを起動させてみましょう。

capture

ドロワーの作成

ドロワーを作ります。 ドロワー内ではタブとタームオブサービススクリーンの切替が可能になります。

root(スイッチ)
    - チュートリアルスクリーン
    - ドロワー  // ここ
        - タブ(完成)
            - ホームスタック(完成)
                - ホームスクリーン(完成)
                - ホーム2スクリーン(完成)
            - プロフィールスタック(完成)
                - プロフィールスクリーン(完成)
                - プロフィールエディットスクリーン(完成)
            - セッティングスクリーン(完成)
        - タームオブサービススクリーン

AppNavigator.jsに追記しましょう。

import {
  createStackNavigator,
  createBottomTabNavigator,
  createDrawerNavigator,
  createSwitchNavigator
} from 'react-navigation'

import HomeScreen from '../screens/HomeScreen'
import Home2Screen from '../screens/Home2Screen'
import ProfileScreen from '../screens/ProfileScreen'
import ProfileEditScreen from '../screens/ProfileEditScreen'
import SettingScreen from '../screens/SettingScreen'

const HomeStack = createStackNavigator(
  {
    Home: {
      screen: HomeScreen
    },
    Home2: {
      screen: Home2Screen
    },
  },
  {
    initialRouteName: "Home",
  }
)

const ProfileStack = createStackNavigator(
  {
    Profile: {
      screen: ProfileScreen
    },
    ProfileEdit: {
      screen: ProfileEditScreen
    },
  },
  {
    initialRouteName: "Profile",
  }
)

const Tab = createBottomTabNavigator(
  {
    Home: HomeStack,
    Profile: ProfileStack,
    Setting: {
      screen: SettingScreen,
    },
  }
)

const Drawer = createDrawerNavigator({
  App: Tab,
  TermOfService: TermOfService,
})

export default Drawer

createDrawerNavigatorを使って、ドロワーを作成します。

ドロワーの中には、タブタームオブサービススクリーンが入るので、Appをキーにタブを、TermOfServiceをキーにタームオブサービススクリーンを設定しています。

最後にDrawerexportしておきます。

const Drawer = createDrawerNavigator({
  App: Tab,
  TermOfService: TermOfServiceScreen,
})

export default Drawer

ドロワーが完成しました。

root(スイッチ)
    - チュートリアルスクリーン
    - ドロワー(完成)
        - タブ(完成)
            - ホームスタック(完成)
                - ホームスクリーン(完成)
                - ホーム2スクリーン(完成)
            - プロフィールスタック(完成)
                - プロフィールスクリーン(完成)
                - プロフィールエディットスクリーン(完成)
            - セッティングスクリーン(完成)
        - タームオブサービススクリーン(完成)

ドロワーの動きの確認

一度動きの確認をします。

yarn startexpoを起動させてみましょう。

capture

スイッチの作成

スイッチを作ります。 スイッチ内ではチュートリアルスクリーンとドロワーの切替が可能になります。

root(スイッチ)  // ここ
    - チュートリアルスクリーン
    - ドロワー(完成)
        - タブ(完成)
            - ホームスタック(完成)
                - ホームスクリーン(完成)
                - ホーム2スクリーン(完成)
            - プロフィールスタック(完成)
                - プロフィールスクリーン(完成)
                - プロフィールエディットスクリーン(完成)
            - セッティングスクリーン(完成)
        - タームオブサービススクリーン(完成)

AppNavigator.jsに追記しましょう。

import {
  createStackNavigator,
  createBottomTabNavigator,
  createDrawerNavigator,
  createSwitchNavigator
} from 'react-navigation'

import HomeScreen from '../screens/HomeScreen'
import Home2Screen from '../screens/Home2Screen'
import ProfileScreen from '../screens/ProfileScreen'
import ProfileEditScreen from '../screens/ProfileEditScreen'
import SettingScreen from '../screens/SettingScreen'
import TermOfServiceScreen from '../screens/TermOfServiceScreen'
import TutorialScreen from '../screens/TutorialScreen'

const HomeStack = createStackNavigator(
  {
    Home: {
      screen: HomeScreen
    },
    Home2: {
      screen: Home2Screen
    },
  },
  {
    initialRouteName: "Home",
  }
)

const ProfileStack = createStackNavigator(
  {
    Profile: {
      screen: ProfileScreen
    },
    ProfileEdit: {
      screen: ProfileEditScreen
    },
  },
  {
    initialRouteName: "Profile",
  }
)

const Tab = createBottomTabNavigator(
  {
    Home: HomeStack,
    Profile: ProfileStack,
    Setting: {
      screen: SettingScreen,
    },
  }
)

const Drawer = createDrawerNavigator({
  App: Tab,
  TermOfService: TermOfServiceScreen,
})

const AppNavigator = createSwitchNavigator({
  Tutorial: {
    screen: TutorialScreen,
  },
  Main: Drawer,
})

export default AppNavigator

createSwitchNavigatorを使って、スイッチを作成します。

スイッチの中には、チュートリアルスクリーンドロワーが入るので、Tutorialをキーにチュートリアルスクリーンを、Mainをキーにドロワーを設定しています。

最後にAppNavigatorexportしておきます。

const AppNavigator = createSwitchNavigator({
  Tutorial: {
    screen: TutorialScreen,
  },
  Main: Drawer,
})

export default AppNavigator

TutorialからMainへで切替を行えるよう修正します。 チュートリアルスクリーンを下記のように修正しましょう。

import React, { Component } from 'react'
import { Platform, StyleSheet, View, Text, Button } from 'react-native'

class TutorialScreen extends Component {
  render () {
    return (
      <View style={styles.container}>
        <Text>Tutorial</Text>
        <Button
          title="go to Main"
          onPress={() => this.props.navigation.navigate('Main')}
        />
      </View>
    )
  }
}

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

export default TutorialScreen

スタックの作成で説明したスクリーンの切替はスクリーン以外のドロワーでも切替できます。 ようは引数にキーを入れれば切替が発生します。

this.props.navigation.navigate('キー')

スイッチが完成しました。

root(スイッチ)(完成)
    - チュートリアルスクリーン(完成)
    - ドロワー(完成)
        - タブ(完成)
            - ホームスタック(完成)
                - ホームスクリーン(完成)
                - ホーム2スクリーン(完成)
            - プロフィールスタック(完成)
                - プロフィールスクリーン(完成)
                - プロフィールエディットスクリーン(完成)
            - セッティングスクリーン(完成)
        - タームオブサービススクリーン(完成)

スイッチの動きの確認

最終チェックです、動きの確認をします。

yarn startexpoを起動させてみましょう。

capture

さいごに

はじめに構造を考えてから、create[ XXX ]Navigatorを使って構築していけばうまく行くはずです。 react-nativeでのアプリ開発では欠かせないライブラリだと思いますので、ぜひreact-navigation の使い方覚えちゃいましょう。

サンプルコードgithubにあげてます。 https://github.com/kousaku-maron/react-navigation-sample-for-qiita