React-Nativeを使ってiOSアプリを作ってみる(その2 画面遷移)

# はじめに

[React-Nativeを使ってiOSアプリを作ってみる(その1 環境構築) ](https://qiita.com/rsm223_rip/items/f70c9c8939a773398b87)
👆これの続きです。

画面遷移周りのについて書いてみようと思います。
Reactでは画面遷移にnavigatorとかいうのを使っているらしい。
例に漏れず、React-Nativeでもnavigatorを使って遷移している。
画面遷移のnavigatorはstack/tab/drawとかあるっぽい
[React Navigation(公式)](https://reactnavigation.org/)

# 環境構築

👇の感じでやれば、取り敢えずOKっぽい
Drawerで`babel.config.js`いじったり、何かパッケージ入れたりもするけど忘れたので割愛。  
(エラーの内容をstackoverflowで検索すれば解決するはず)

```bash
npm install @react-navigation/native
npm install react-native-screens react-native-safe-area-context

# stack navigation関連
npm install @react-navigation/native-stack

# Tab navigation関連
npm install @react-navigation/bottom-tabs

# Drawer navigation関連
npm install @react-navigation/drawer
npm install react-native-gesture-handler react-native-reanimated
```

上記のインストール後、iosディレクトリでiOSのライブラリを更新する
(Androidだと`pod update`の代わりにJavaのファイルを弄らないといけないっぽい)

```bash
# iosディレクトリ
pod update

# update後、反映されない場合
# キャッシュをクリアして実行すると解決されたりする
npm start -- --reset-cache
```

# Stack Navigatorを使ってみる

ファイルを作ったりはめんどくさいので、index.jsのみで実装する

```jsx:index.js
/**
 * @format
 */
import React, { Component, useState, useRef } from 'react';
import { AppRegistry, Text, View, Button, } from 'react-native';
import { name as appName } from './app.json';

// 👇これらをインポートしないとnavigatorが使えない
import 'react-native-gesture-handler';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function MakePageFunc(num) {
    return function ({ navigation }) {
        return (
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
                <Text>Page No.{num}</Text>
                <Button title={`Go to Page No. ${((num + 1) % 3)}`}
                    onPress={() => navigation.navigate("Page" + ((num + 1) % 3))}
                />
            </View>
        );
    };
}

const Stack = createNativeStackNavigator();

function StackScreen() {
    return (
        <Stack.Navigator>
            <Stack.Screen name="Page0" component={MakePageFunc(0)} />
            <Stack.Screen name="Page1" component={MakePageFunc(1)} />
            <Stack.Screen name="Page2" component={MakePageFunc(2)} />
        </Stack.Navigator>
    );
}

class temp extends Component {
    render() {
        return (
            <NavigationContainer>
                <StackScreen />
            </NavigationContainer>
        );
    }
}

AppRegistry.registerComponent(appName, () => temp);
```

---

# Tab Navigatorを使ってみる

使い方はstackと同じ

```diff_jsx:index
/**
 * @format
 */

import React, { Component, useState, useRef } from 'react';
import { AppRegistry, Text, View, Button, } from 'react-native';
import 'react-native-gesture-handler';
import { name as appName } from './app.json';

// 👇これらをインポートしないとnavigatorが使えない
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

function MakePageFunc(num) {
    return function ({ navigation }) {
        return (
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
                <Text>Page No.{num}</Text>
                <Button title={`Go to Page No. ${((num + 1) % 3)}`}
                    onPress={() => navigation.navigate("Page" + ((num + 1) % 3))}
                />
            </View>
        );
    };
}

const Tab = createBottomTabNavigator();

function TabScreen() {
    return (
        <Tab.Navigator>
            <Tab.Screen name="Page0" component={MakePageFunc(0)} />
            <Tab.Screen name="Page1" component={MakePageFunc(1)} />
            <Tab.Screen name="Page2" component={MakePageFunc(2)} />
        </Tab.Navigator>
    );
}

class temp extends Component {
    render() {
        return (
            <NavigationContainer>
                <TabScreen />
            </NavigationContainer>
        );
    }
}

AppRegistry.registerComponent(appName, () => temp);
```

# Draw Navigatorを使う

実行前に`babel.config.js`を更新。
Drawer NativeはStack/Tabと変わらない。

```diff_javascript:babel.config.js
module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
+  plugins: [
+    'react-native-reanimated/plugin'
+  ]
};
```

```jsx:index.js
import React, { Component, useState, useRef } from 'react';
import { AppRegistry, Text, View, Button, } from 'react-native';
import 'react-native-gesture-handler';
import { name as appName } from './app.json';

// 👇これらをインポートしないとnavigatorが使えない
import { NavigationContainer } from '@react-navigation/native';
import { createDrawerNavigator } from '@react-navigation/drawer';

function MakePageFunc(num) {
    return function ({ navigation }) {
        return (
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
                <Text>Page No.{num}</Text>
                <Button title={`Go to Page No. ${((num + 1) % 3)}`}
                    onPress={() => navigation.navigate("Page" + ((num + 1) % 3))}
                />
            </View>
        );
    };
}

const Draw = createDrawerNavigator();

function DrawScreen() {
    return (
        <Draw.Navigator>
            <Draw.Screen name="Page0" component={MakePageFunc(0)} />
            <Draw.Screen name="Page1" component={MakePageFunc(1)} />
            <Draw.Screen name="Page2" component={MakePageFunc(2)} />
        </Draw.Navigator>
    );
}

class temp extends Component {
    render() {
        return (
            <NavigationContainer>
                <DrawScreen />
            </NavigationContainer>
        );
    }
}

AppRegistry.registerComponent(appName, () => temp);
```

# まとめ

以上、上記の感じで画面遷移を実装できる。
また、DrawerとStackを組み合わせて使うこともできるらしいです。

次は、C++でのモジュール作成方法について書いていきます。
[React-Nativeを使ってiOSアプリを作ってみる(その3 C++でモジュール作成)](https://qiita.com/rsm223_rip/items/a85f70043024776875f3)