ReactNativeのナビゲーション

# ナビゲーション
## ライブラリインストール
公式を参考にした
https://reactnavigation.org/docs/5.x/getting-started/


```
npm install @react-navigation/native@5.9.8
```
最新のは６系があるが書き方が変わるため、とりあえず５で試した

expoの依存ライブラリインストール

```
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
```


```
npm install @react-navigation/stack@5.14.9
```

# ナビゲーションを登録
App.jsx

```jsx
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

import MemoListScreen from './src/screens/MemoListScreen';
import MemoDetailScreen from './src/screens/MemoDetailScreen';
import MemoEditScreen from './src/screens/MemoEditScreen';
import MemoCreateScreen from './src/screens/MemoCreateScreen';
import LoginScreen from './src/screens/LoginScreen';
import SignUpScreen from './src/screens/SignUpScreen';

const Stack = createStackNavigator();
// eslint-disable-next-line react/function-component-definition
export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator
        initialRouteName="MemoListScreen"
        screenOptions={{
          headerStyle: { backgroundColor: '#C51162' },
          headerTitleStyle: { color: '#fff' },
          headerTitle: 'Memo',
          headerTintColor: '#fff',
          headerBackTitle: 'Back',
        }}
      >
        <Stack.Screen name="MemoListScreen" component={MemoListScreen} />
        <Stack.Screen name="MemoDetailScreen" component={MemoDetailScreen} />
        <Stack.Screen name="MemoEditScreen" component={MemoEditScreen} />
        <Stack.Screen name="MemoCreateScreen" component={MemoCreateScreen} />
        <Stack.Screen name="LoginScreen" component={LoginScreen} />
        <Stack.Screen name="SignUpScreen" component={SignUpScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}
```

Stack.Navigatorの中で、
initialRouteNameは最初のページの遷移指定できる。
screenOptionsではアプリのヘッダーを書き換えることができる。


## ボタンを押してページを遷移する
メモリストのページで、右下のボタンを押したら新規作成ページを遷移するように変更する。
![図11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2284107/43eb0f22-2bd2-1a24-e58f-b5a2d249b96c.jpeg)

MemoListScreen.jsx

```jsx
import React from 'react';
import { View, StyleSheet } from 'react-native';

import CircleButton from '../components/CircleButton';
import MemoList from '../components/MemoList';

// eslint-disable-next-line react/function-component-definition
export default function MemoListScreen(props) {
  const { navigation } = props;
  return (
    <View style={styles.container}>
      <MemoList />

      <CircleButton
        name="plus"
        onPress={() => { navigation.navigate('MemoCreateScreen'); }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#FCE4EC',
  },
});
```

propsでnavigationを受け取る。
CircleButtonタグの中で、
onPressに() => { navigation.navigate('MemoCreateScreen')と渡してあげればページ遷移することができる。

通常、propsで何かを受け取るときは、型や初期値を定義するが、navigationはreact-nativeのデフォルトのものなので、
毎回定義するのはめんどくさい。
そこで、ESLintにnavigationは型や初期値を定義しなくても良いというルールを追加する。
rulesの中に"react/prop-types": ["error", { "ignore": ["navigation"] }]を追加。

```json
{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "plugin:react/recommended",
        "airbnb"
    ],
    "parserOptions": {
        "ecmaFeatures": {
            "jsx": true
        },
        "ecmaVersion": 13,
        "sourceType": "module"
    },
    "plugins": [
        "react"
    ],
    "rules": {
        "no-use-before-define": 0,
        "react/prop-types": ["error", { "ignore": ["navigation"] }]
    }
}
```


## １つ前のページに戻るとき

```jsx
<CircleButton
  name="plus"
  onPress={() => { navigation.goBack(); }}
/>
```

## 戻るボタンをつけたくないとき
react navigatorはページをスタックしていくイメージ。
ログイン画面でSubmitを押すとメモリストの画面に遷移し、アプリのヘッダーに戻るボタン(Back)が付いてしまう。
ログインしたあとは、ログイン画面に戻る必要はないので、戻るボタンの表示を消す。

![図12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2284107/9cbdcde0-ab26-9cb5-0caa-d3faaa02fe31.png)

LoginScreen.jsxでNavigation.navigateでメモリスト画面に遷移させていたのを変更する。

LoginScreen.jsx　変更前

```jsx
import React from 'react';
import {
  View, Text, TextInput, StyleSheet, TouchableOpacity,
} from 'react-native';

import Button from '../components/Button';

// eslint-disable-next-line react/function-component-definition
export default function LoginScreen(props) {
  const { navigation } = props;
  return (
    <View style={styles.container}>

      <View style={styles.inputContainer}>
        <Text style={styles.inputTitle}>Login</Text>
        <TextInput value="id" style={styles.input} />
        <TextInput value="pass" style={styles.input} />

        <Button
          onPress={() => { navigation.navigate('MemoListScreen'); }}
        >
          Submit
        </Button>

        <View>
          <Text style={styles.footerText}>Not resistered?</Text>
          <TouchableOpacity>
            <Text style={styles.footerLink}>Sigh up here</Text>
          </TouchableOpacity>
        </View>

      </View>

    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#FCE4EC',
  },
  inputContainer: {
    paddingHorizontal: 24,
    paddingVertical: 24,
  },
  inputTitle: {
    fontSize: 24,
    lineHeight: 40,
    fontWeight: 'bold',
    marginBottom: 14,
  },
  input: {
    fontSize: 16,
    height: 40,
    backgroundColor: '#fff',
    borderColor: '#ddd',
    borderWidth: 1,
    paddingHorizontal: 14,
    marginBottom: 10,
  },
  footerText: {
    fontSize: 16,
    lineHeight: 32,
  },
  footerLink: {
    fontSize: 16,
    lineHeight: 32,
    color: '#D81B60',
  },
});
```

navigation.resetを使う。
routesには履歴をリストで保持して、
indexはroutesの何番めに遷移するかを指定できる。

LoginScreen.jsx　変更後

```jsx
<Button
  onPress={() => {
    navigation.reset({
      index: 0,
      routes: [{ name: 'MemoListScreen' }],
    });
  }}
>
  Submit
</Button>
```