Help us understand the problem. What is going on with this article?

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

はじめに

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

画面構成

スクリーンショット 2020-02-22 12.05.48.png

React Navigation

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

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

App

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に渡してまとめることで、ネストしたルーティングを実現します。

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

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

Containers

Signup.tsx

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

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

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)でログインフォーム⑤ 〜入力フォームとログインロジックの実装〜

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした