React Native

【ReactNavigation】ボトムタブを遷移ごとに切り変える方法

React Native
この記事は約12分で読めます。

ReactNavigation の学習を進めていく中で、下タブの切り替え方法のロジックがどうなってるのか気になったことがあり、その内容を共有していきます。
下の Snack で確認できます。

MultipleBottomTabs - Snack
Try this project on your phone! Use Expo's online editor to make changes and save your own copy.

ココからは、上記snackでの実装の説明となります。

import * as React from 'react';
import { Text, View, Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createStackNavigator } from '@react-navigation/stack';

const Navigation = NavigationContainer;
const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();

function FeedScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: 'center' }}>
      <Button
        title="遷移したら下タブを変更"
        onPress={() => navigation.navigate('Settings')}
      />
    </View>
  );
}

function HomeTabs() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Feed" component={FeedScreen} />
      <Tab.Screen name="Profile" component={ProfileScreen} />
    </Tab.Navigator>
  );
}

export default function App() {
  return (
    <Navigation>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeTabs} />
      </Stack.Navigator>
    </Navigation>
  );
}

まず初めに、簡単な雛形を用意しました。

const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();

BottomTab は createBottomTabNavigator()、Stack は createStackNavigator() を使うことで遷移ができます。Navigation を有効にするには、それらをNavigationContainer でラップする必要があるので、忘れないようにしましょう。
この辺りは、公式ドキュメントを追えば完結すると思います。

React Navigation | React Navigation
Routing and navigation for your React Native apps

ただ、今の状態では、ボタンを押しても次の画面に遷移しません。
というのも、Stack.Screenには1つの遷移先しかないため、加えていく必要があります。

function FeedScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: 'center' }}>
      <Button
        title="遷移したら下タブを変更"
        onPress={() => navigation.navigate('Settings')}
      />
    </View>
  );
}

function ProfileScreen() {return <View />}

function SettingsScreen({navigation}) {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Settings1" component={SettingFirstScreen} />
      <Tab.Screen name="Settings2" component={SettingSecondScreen} />
    </Tab.Navigator>
  )
}

function HomeTabs() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Feed" component={FeedScreen} />
      <Tab.Screen name="Profile" component={ProfileScreen} />
    </Tab.Navigator>
  );
}

export default function App() {
  return (
    <Navigation>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeTabs} />
        <Stack.Screen name="Settings" component={SettingsScreen} />
      </Stack.Navigator>
    </Navigation>
  );
}

ココでも、ボタンを押したらエラーが出ます。ココが重要ポイントなのですが、SettingsScreenには、新たに、Tab.Navigator と、その遷移先の画面だけしか置いてません。
こうすることで、遷移先の画面では、別のタブで切り替えられるように表示することができます。下記のように変更しましょう。

function FeedScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: 'center' }}>
      <Button
        title="遷移したら下タブを変更"
        onPress={() => navigation.navigate('Settings')}
      />
    </View>
  );
}

function ProfileScreen() {return <View />}

function SettingsScreen({navigation}) {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Settings1" component={SettingFirstScreen} />
      <Tab.Screen name="Settings2" component={SettingSecondScreen} />
    </Tab.Navigator>
  )
}


function SettingFirstScreen({ navigation }) {
  return (    
    <View style={{ flex: 1, justifyContent: 'center' }}>
      <Button
        title="Accountスクリーンに行くと下タブが変わる"
        onPress={() => navigation.navigate('Account')}
      />
    </View>
  )
}

function SettingSecondScreen({ navigation }) {
  return (    
    <View style={{ flex: 1, justifyContent: 'center' }}>
      <Button
        title="Settings2"
        onPress={() => navigation.goBack()}
      />
    </View>
  )
}

function HomeTabs() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Feed" component={FeedScreen} />
      <Tab.Screen name="Profile" component={ProfileScreen} />
    </Tab.Navigator>
  );
}

export default function App() {
  return (
    <Navigation>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeTabs} />
        <Stack.Screen name="Settings" component={SettingsScreen} />
      </Stack.Navigator>
    </Navigation>
  );
}

SettingsScreen が管理しているタブへと遷移できるようになります。コレを繰り返すことで、3つの下タブ切り替えだったり、4つの下タブ切り替えだったり、、ということが行えるようになります。

こちらが最終形となります。

function FeedScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: 'center' }}>
      <Button
        title="遷移したら下タブを変更"
        onPress={() => navigation.navigate('Settings')}
      />
    </View>
  );
}

function ProfileScreen() {return <View />}

function SettingsScreen({navigation}) {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Settings1" component={SettingFirstScreen} />
      <Tab.Screen name="Settings2" component={SettingSecondScreen} />
    </Tab.Navigator>
  )
}


function SettingFirstScreen({ navigation }) {
  return (    
    <View style={{ flex: 1, justifyContent: 'center' }}>
      <Button
        title="Accountスクリーンに行くと下タブが変わる"
        onPress={() => navigation.navigate('Account')}
      />
    </View>
  )
}

function SettingSecondScreen({ navigation }) {
  return (    
    <View style={{ flex: 1, justifyContent: 'center' }}>
      <Button
        title="Settings2"
        onPress={() => navigation.goBack()}
      />
    </View>
  )
}

function AccountFirstScreen({ navigation }) {
  return (    
    <View style={{ flex: 1, justifyContent: 'center' }}>
      <Button
        title="Account"
        onPress={() => navigation.goBack()}
      />
    </View>
  )
}

function AccountScreen({navigation}) {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Account1" component={AccountFirstScreen} />
    </Tab.Navigator>
  )
}


function HomeTabs() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Feed" component={FeedScreen} />
      <Tab.Screen name="Profile" component={ProfileScreen} />
    </Tab.Navigator>
  );
}

export default function App() {
  return (
    <Navigation>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeTabs} />
        <Stack.Screen name="Settings" component={SettingsScreen} />
        <Stack.Screen name="Account" component={AccountScreen} />
      </Stack.Navigator>
    </Navigation>
  );
}