Expo+Redux(+firebase)でログインフォーム④　〜ReactNavigationを使った画面遷移〜

# はじめに
[Expo+Redux(+firebase)でログインフォーム③　〜ファイル整理・Debugger〜](https://qiita.com/AtsushiNi/items/13fc1f94674d9614e43f)　の続きです。
この記事では、ログイン画面を作り、ReactNavigationで画面遷移をできるようにしていきます。
まだログインのロジック自体は実装していないので、ボタンをクリックすると画面遷移されるようにしておきます。

# 画面構成

<img width="376" alt="スクリーンショット 2020-02-22 12.05.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549051/19922def-30c5-645e-e8c0-3be7fb67783c.png">

# React Navigation

2020/2/22時点での最新は5.xです
3.xや4.xとは文法が変わっているので、ネットの記事を参考にする際は注意してください！！(僕はこれでハマりました)

Reduxとの共存ですが、App.tsxとコンポーネントをいじるだけで使えるようになります。
storeやmodulesを気にせず使えるので便利ですね

# App
```Javascript:src/App.tsx
import React from 'react';
import { Provider } from 'react-redux'
import { NavigationContainer } from '@react-navigation/native'
import { createStackNavigator } from '@react-navigation/stack'
import store from './store'
import CounterContainer from './containers/Counter'
import StaticCounterContainer from './containers/StaticCounter'
import SigninContainer from './containers/Signin'
import SignupContainer from './containers/Signup'


export default function App() {
  // サインイン中のScreen
  const SignedInStack = createStackNavigator()

  const SignedInStackScreen = () => {
    return (
      <SignedInStack.Navigator>
        <SignedInStack.Screen name='Counter' component={CounterContainer} />
        <SignedInStack.Screen name='StaticCounter' component={StaticCounterContainer} />
      </SignedInStack.Navigator>
    )
  }

  // サインアウト後のスクリーン(Auth関連の画面)
  const SignedOutStack = createStackNavigator()

  const SignedOutStackScreen = () => {
    return (
      <SignedOutStack.Navigator>
        <SignedOutStack.Screen name='Signin' component={SigninContainer} />
        <SignedOutStack.Screen name='Signup' component={SignupContainer} />
      </SignedOutStack.Navigator>
    )
  }

  // RootのScreen(ローディング画面、サインイン中、サインアウト後)
  const RootStack = createStackNavigator()

  const RootStackScreen = () => (
    <RootStack.Navigator>
      <RootStack.Screen name='SignedIn' component={SignedInStackScreen} options={{ headerShown: false }}/>
      <RootStack.Screen name='SignedOut' component={SignedOutStackScreen} options={{ headerShown: false }} />
    </RootStack.Navigator>
  )
  return (
    <Provider store={store}>
      <NavigationContainer>
        <RootStackScreen />
      </NavigationContainer>
    </Provider>
  )
}
```

StackNavigationを使用しています
createStackNavigator()で各スクリーンのナビゲーターを作り、それを使ってスクリーンを作っています。
ログイン中とログアウト中のスクリーンをそれぞれ作ったら、それらをcomponentとしてRootStackに渡してまとめることで、ネストしたルーティングを実現します。

```Javascript:src/App.tsx
  return (
    <Provider store={store}>
      <NavigationContainer>
        <RootStackScreen />
      </NavigationContainer>
    </Provider>
  )
```

Providerの内側にNavigationContainerを置くのを忘れないようにしましょう。

# Containers

### Signup.tsx
```Javascript:src/containers/Signup.ts
import { connect } from 'react-redux'
import Signup from '../components/Signup'

const SignupContainer = connect()(Signup)

export default SignupContainer
```
Signup画面では、使うpropsはnavigationだけですが、これはconnect関数に渡さなくともReactNavigationがよしなにしてくれるっぽいです。なので、mapStateToProps, dispatchToPropsは共に使いません。
Signin.tsもほぼこれと変わらないので、省略します。
Counter.tsは前回の記事から変更はありません。

# Components

### Signup.tsx
```Javascript:src/components/Signup.tsx
import React from 'react'
import { View, Text, Button } from 'react-native'
import styles from '../Styles'

const Signup = ({ navigation }) => (
  <View style={styles.container}>
    <Text style={styles.paragraph}>Signup</Text>
    <Button
      title='Go to Signin'
      onPress={() => navigation.navigate('Signin')}
    />
    <Button
      title='Go to Counter'
      onPress={() => navigation.navigate('Counter')}
    />
  </View>
)

export default Signup
```
propでnavigationを受け取っています。これはContainerから受け取ったものではなくReactNavigationが提供しているものです。
画面遷移するには、navigation.navigate()に移動したいスクリーンの名前を渡します。
navigate()だけでなく、goBack()等あるので、公式ドキュメントを参考に。

### Counter.tsx
```Javascript:src/components/Counter.tsx
import React from 'react'
import { View, Text, Button } from 'react-native'
import styles from '../Styles'

const Counter = ({ count, increment, decrement, navigation }) => (
  <View style={styles.container}>
    <Text style={styles.paragraph}>{count}</Text>
    <Button
      title='Increment'
      onPress={increment}
    />
    <Button
      title='DECREMENT'
      onPress={decrement}
    />
    <Button
      title='Go to Static Count page'
      onPress={() => navigation.navigate('StaticCounter')}
    />
    <Button
      title='Go to SignedOut'
      onPress={() => navigation.navigate('SignedOut', { screen: 'Signup' } )}
    />
  </View>
)

export default Counter
```
Signup.tsxとあまり変わらないですね。
'Go to SignedOut'のコールバックのように、ネストした深いスクリーンまで指定して画面遷移したい場合は、スクリーンの名前の後に、paramsに{ screen: "スクリーンの名前" }を加えると実現できます。
ここで、いきなりnavigation.navigate('Signup')とすると、スクリーンが見つからずエラーになるので気をつけましょう。

### 次回
上と同じようにSignin画面、StaticCounter画面を作れば、ボタンを押すことで画面遷移を行えるようになりました。
次回では、フォームの作成とfirebaseのAuthenticationを用いたパスワード認証を実装していきましょう。
[Expo+Redux(+firebase)でログインフォーム⑤　〜入力フォームとログインロジックの実装〜](https://qiita.com/AtsushiNi/items/47c53d43dc12d8246d08)