Fusic Tech Blog

Fusion of Society, IT and Culture

React Native + Expo + TypeScriptで作るモバイルアプリ (Part2 - React Navigation編)
2019/11/05

React Native + Expo + TypeScriptで作るモバイルアプリ (Part2 - React Navigation編)

前回 はNativeBaseを利用して見た目部分を作りました。

今回はその続きでReact Navigation を導入して画面間の移動を実現します。

React Navigationの導入

基本的に公式ドキュメントのGetting started に沿っています。

Expo CLIでReact Navigationとその他必要なライブラリをインストールします。

$ expo install react-navigation react-native-gesture-handler react-native-reanimated

React Navigationでもナビゲーション機能がついたタブ を提供していますが、今回はNativeBaseのタブをそのまま使いたいのでシンプルなSwitch Navigator を使って実現します。

そのほかにも一つ前の画面に戻ることができるStack Navigator というものもあります。

まず、ナビゲーションを実現するために、複数画面(FavoriteScreen, CameraScreen)を用意します。

お気に入り画面:

// src/FavoriteScreen/FavoriteScreen.tsx

import React from "react";
import Layout from "../Layout";
import { Text } from "react-native"

const FavoriteScreen = () => {
  return (
    <Layout>
      <Text>Favorite</Text>
    </Layout>
  );
};

export default FavoriteScreen;

カメラ画面:

// src/CameraScreen/CameraScreen.tsx

import React from "react";
import Layout from "../Layout";
import { Text } from "react-native"

const CameraScreen = () => {
  return (
    <Layout>
      <Text>Camera</Text>
    </Layout>
  );
};

export default CameraScreen;

これでホーム、カメラ、お気に入り画面の3画面ができました。

そして、React NavigationのcreateAppContainer(), createSwitchNavigator() を使って各画面を登録します。

import { createAppContainer, createSwitchNavigator } from "react-navigation";
import HomeScreen from "./HomeScreen/HomeScreen";
import FavoriteScreen from "./FavoriteScreen/FavoriteScreen";
import CameraScreen from "./CameraScreen/CameraScreen";

const AppNavigator = createSwitchNavigator(
  {
    Home: {
      screen: HomeScreen
    },
    Favorite: {
      screen: FavoriteScreen
    },
    Camera: {
      screen: CameraScreen
    }
  },
  {
    initialRouteName: "Home"
  }
);

export default createAppContainer(AppNavigator);

initialRouteName オプションで初期表示画面を指定します。

最後にApp.tsxで呼び出します。

// App.tsx

import React from 'react';
import AppContainer from './src/AppContainer'
export default function App() {
  return (
    <AppContainer/>
  );
}

これでReact Navigationを使った画面切り替える準備が整いました。

Hooksを使ったナビゲート

Switch Navigatorに遷移させたい画面を登録しました。

あとはNativeBaseのFooterTabコンポーネントが押されたらその画面へ遷移させる処理が必要です。

React Navigationでは NavigationContext というものがあり、Hooks APIの useContext() を一緒に拡張することで、画面遷移処理を実現できます。

// src/hooks/useNavigation.ts

import { useContext } from "react";
import {
  NavigationScreenProp,
  NavigationRoute,
  NavigationContext
} from "react-navigation";

export function useNavigation<T>() {
  return useContext(NavigationContext) as NavigationScreenProp<
    NavigationRoute,
    T
  >;
}

NavigationScreenPropを返しています。

参考: https://github.com/react-navigation/hooks

あとは、遷移させたい箇所で useNavigation()を呼び出すだけです。

今回はフッター部分になります。

// src/Layout.tsx

import React from "react";
import {
  Container,
  Header,
  Title,
  Content,
  Footer,
  FooterTab,
  Button,
  Body,
  Icon
} from "native-base";
import { useNavigation } from "./hooks/useNavigation";

interface IProps {
  children: React.ReactNode;
}

const Layout = (props: IProps) => {
  const navigation = useNavigation();
  return (
    <Container>
      <Header>
        <Body>
          <Title>My App</Title>
        </Body>
      </Header>
      <Content>{props.children}</Content>
      <Footer>
        <FooterTab>
          <Button
            onPress={() => {
              navigation.navigate("Home");
            }}
            active={navigation.state.routeName === "Home"}
          >
            <Icon name="home" />
          </Button>
          <Button
            onPress={() => {
              navigation.navigate("Camera");
            }}
            active={navigation.state.routeName === "Camera"}
          >
            <Icon name="camera" />
          </Button>
          <Button
            onPress={() => {
              navigation.navigate("Favorite");
            }}
            active={navigation.state.routeName === "Favorite"}
          >
            <Icon name="bookmark" />
          </Button>
        </FooterTab>
      </Footer>
    </Container>
  );
};

export default Layout;

これでフッターのタブをタップすると画面が切り替わると思います。

Footer tabs with react navigation

まとめ

React Navigationを導入したことで驚くほど簡単にナビゲーションを実現することができました。 Hooksをサポートしてくれてるのも嬉しいです。

次回はExpo SDKを使ってカメラなどのネイティブ機能を追加したいと思います。

Daiki Urata

Daiki Urata

フロントエンド好きなエンジニアです。