react-navigation v5でタブナビゲーション作成

## 前提

expoを使用しています。

## react-navigation

react-navigationはReact Nativeで画面遷移を実装するためのライブラリです。
導入に当たって記事を探していたところ、v4とだいぶ変わっていたようなので参考になれば幸いです。
v4とはパッケージ名から変わっているよう…
似たような名前で記述が違うなあと不思議に思っていたらバージョンのせいだった。


### ナビゲーションの種類

それぞれ公式サイトに動作イメージがついているので見てみるとイメージしやすいです。
今回は、`MaterialTopTabNavigator`を使ってみました。

* [StackNavigator](https://reactnavigation.org/docs/stack-navigator)
* [DrawerNavigator](https://reactnavigation.org/docs/drawer-navigator)
* [BottomTabNavigator](https://reactnavigation.org/docs/bottom-tab-navigator)
* [MaterialTopTabNavigator](https://reactnavigation.org/docs/material-top-tab-navigator)
* [MaterialBottomTabNavigator](https://reactnavigation.org/docs/material-bottom-tab-navigator)

## インストール

[公式サイト](https://reactnavigation.org/docs/getting-started)を参考にしました。

```
// react-native導入
$ npm install @react-navigation/native
$ expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view

// MaterialTopTabNavigator導入
$ npm install @react-navigation/material-top-tabs react-native-tab-view

```

## タブナビゲーションを表示してみる

サンプルコードがあるので、その通りに記載してみる。

```App.js
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';

// Homeタブで表示される画面内容
function HomeScreen() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Home!</Text>
    </View>
  );
}

// Settingタブで表示される画面内容
function SettingsScreen() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Settings!</Text>
    </View>
  );
}

// タブを表示するための記述
const Tab = createMaterialTopTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}
```
HomeとSettingsタブが作成されました。
<img width="300px" alt="タブナビゲーション" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102996/fc981137-c342-11d7-06a2-a5035ae9d361.png">

※iPhoneXなどノッチ部分があるとナビゲーションとかぶってしまうので、対応が必要そうです
※参考URL：[react-navigation V5](https://dev-yakuza.github.io/react-native/react-navigation-v5/)

## ファイル構成をいい感じにしてみる

表示するだけならこのままで問題ありませんが、
今後しっかり記述していくのであれば、ナビゲーション部分と画面部分で記述を分けたいので対応。

### ファイル構成
```
$ tree -I node_modules
.
├── App.js
├── README.md
├── app.json
├── assets
│   ├── icon.png
│   └── splash.png
├── babel.config.js
├── navigation
│   └── AppNavigator.js // 作成
├── package-lock.json
├── package.json
└── screens
    ├── HomeScreen.js  // 作成
    └── SettingScreen.js  // 作成
```

画面の表示部分は`screens`配下にまとめ、ナビゲーションは`AppNavigator.js`に記述。
`AppNavigator.js`を`App.js`で呼び出してあげることですっきりしました。

### 画面表示部分

App.jsに記載していた画面表示の記述をファイルに切り出します。

移行前

```App.js
// Homeタブで表示される画面内容
function HomeScreen() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Home!</Text>
    </View>
  );
}

// Settingタブで表示される画面内容
function SettingsScreen() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Settings!</Text>
    </View>
  );
}
```

移行後

```HomeScreen.js
import React, { Component } from 'react';
import { Text, View } from 'react-native';

export default class HomeScreen extends Component {
    render() {
        return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Text>Home!</Text>
        </View>
        );
    }
}
```

```SettingScreen.js
import React, { Component } from 'react';
import { Text, View } from 'react-native';

export default class SettingScreen extends Component {
    render() {
        return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Text>Settings!</Text>
        </View>
        );
    }
}
```

### ナビゲーション部分

App.jsに記載していたナビゲーションの記述もファイルに切り出します。

移行前

```App.js
// タブを表示するための記述
const Tab = createMaterialTopTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}
```

移行後

```AppNavigator.js
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import HomeScreen from '../screens/HomeScreen';
import SettingScreen from '../screens/SettingScreen';

const Tab = createMaterialTopTabNavigator();

export default function AppNavigator() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Settings" component={SettingScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}
```

### ナビゲーションを表示

App.jsからナビゲーションの処理を呼び出します。
これで、表示は変わらずファイルを切り出すことができました。

```App.js
import * as React from 'react';
import AppNavigator from './navigation/AppNavigator';

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

## まとめ

React Nativeに初めて触っているので、ファイルの切り出し方すらよく分からず試行錯誤しました。
初心者の方の参考になれば幸いです。

## 参考URL
[React Navigation](https://reactnavigation.org/)
[react-navigation V5](https://dev-yakuza.github.io/react-native/react-navigation-v5/)
[[React Native] Todoアプリつくってみた](https://note.com/daisuke_mori/n/nc9fc9c19724c)
[【v4 -> v5変更点、v5使い方】react-navigationV5でちゃった・・・// 【react-native】](https://qiita.com/YutamaKotaro/items/e3bc6a16237fc241ef7c)