React navigation hide one tab

Viewed 6607

I'm using react-navigation for navigating between screens. Is it possible to have createBottomTabNavigator with 3 tabs, but when you show tab bar, I want to have visible only 2 tabs instead of 3. ?

5 Answers

I made a npm package for this, please see;

https://www.npmjs.com/package/react-navigation-selective-tab-bar

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */

import React, { Component } from "react";
import { Platform, StyleSheet, Text, View, Button } from "react-native";
import { createBottomTabNavigator, createAppContainer } from "react-navigation";
import BottomTabBar from "react-navigation-selective-tab-bar";
class ScreenOne extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>Screen One</Text>
        <Text style={styles.number}>1</Text>
        <Text style={styles.instructions}>
          I AM on the bottom tab Navigator
        </Text>
        <View style={styles.buttons}>
          <Button
            title="One"
            onPress={() => this.props.navigation.navigate("One")}
          />
          <Button
            title="Two"
            onPress={() => this.props.navigation.navigate("Two")}
          />
          <Button
            title="Three"
            onPress={() => this.props.navigation.navigate("Three")}
          />
          <Button
            title="Four"
            onPress={() => this.props.navigation.navigate("Four")}
          />
        </View>
      </View>
    );
  }
}

class ScreenTwo extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>Screen Two</Text>
        <Text style={styles.number}>2</Text>
        <Text style={styles.instructions}>
          I am NOT on the bottom tab Navigator
        </Text>
        <View style={styles.buttons}>
          <Button
            title="One"
            onPress={() => this.props.navigation.navigate("One")}
          />
          <Button
            title="Two"
            onPress={() => this.props.navigation.navigate("Two")}
          />
          <Button
            title="Three"
            onPress={() => this.props.navigation.navigate("Three")}
          />
          <Button
            title="Four"
            onPress={() => this.props.navigation.navigate("Four")}
          />
        </View>
      </View>
    );
  }
}

class ScreenThree extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>Screen Three</Text>
        <Text style={styles.number}>3</Text>
        <Text style={styles.instructions}>
          I AM on the bottom tab Navigator
        </Text>
        <View style={styles.buttons}>
          <Button
            title="One"
            onPress={() => this.props.navigation.navigate("One")}
          />
          <Button
            title="Two"
            onPress={() => this.props.navigation.navigate("Two")}
          />
          <Button
            title="Three"
            onPress={() => this.props.navigation.navigate("Three")}
          />
          <Button
            title="Four"
            onPress={() => this.props.navigation.navigate("Four")}
          />
        </View>
      </View>
    );
  }
}

class ScreenFour extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>Screen Four</Text>
        <Text style={styles.number}>4</Text>
        <Text style={styles.instructions}>
          I am NOT on the bottom tab Navigator
        </Text>
        <View style={styles.buttons}>
          <Button
            title="One"
            onPress={() => this.props.navigation.navigate("One")}
          />
          <Button
            title="Two"
            onPress={() => this.props.navigation.navigate("Two")}
          />
          <Button
            title="Three"
            onPress={() => this.props.navigation.navigate("Three")}
          />
          <Button
            title="Four"
            onPress={() => this.props.navigation.navigate("Four")}
          />
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#F5FCFF"
  },
  welcome: {
    fontSize: 20,
    textAlign: "center",
    margin: 10
  },
  instructions: {
    textAlign: "center",
    color: "#333333",
    marginBottom: 5
  },
  number: {
    fontSize: 50
  },
  buttons: {
    flexDirection: "row"
  }
});

const AppNavigator = createBottomTabNavigator(
  {
    One: {
      screen: ScreenOne
    },
    Two: {
      screen: ScreenTwo
    },
    Three: {
      screen: ScreenThree
    },
    Four: {
      screen: ScreenFour
    }
  },
  {
    tabBarComponent: props => {
      return (
        <BottomTabBar
          {...props} // Required
          display={["One", "Three"]} // Required
          background="black" // Optional
        />
      );
    }
  }
);

export default createAppContainer(AppNavigator);

Put your third item/screen in a stack navigator:

const Bottom = createBottomTabNavigator({
    item1: {screen: Screen1},
    item2: {screen: Screen2},
    },{
        initialRouteName: "item1",
    }
)

export default createStackNavigator({
    tabs: Bottom,
    item3: Screen3,
})

At last, to change the screen to your third route in your component, you can do this:

// ... 
import {withNavigation} from 'react-navigation' // IMPORTANT
export default class Example extends React.Component{
    render(){
        return(
            <TouchableOpacity onPress={() => this.props.navigation.navigate('item3')}>
        )
    }
}

export default withNavigation(Example) // IMPORTANT

https://github.com/react-navigation/react-navigation/issues/5230#issuecomment-649206507

Here is how you can tell the tab navigator to not render certain routes.

<Tab.Navigator
  screenOptions={({ route }) => ({
    tabBarButton: [
      "Route1ToExclude",
      "Route2ToExclude"
    ].includes(route.name)
      ? () => {
          return null;
        }
      : undefined,
  })}
>

This worked for me, you are still able to navigate to the tab! I changed it to this:

Without a variable:

tabBarButton: ["About"].includes(route.name) ? () => null : undefined

With a variable to hide specific tabs:

const hiddenTabs = ["About", "Food"];
tabBarButton: hiddenTabs.includes(route.name) ? () => null : undefined

With a variable to show specific tabs only:

const tabsToShow = ["About", "Food"];
tabBarButton: !tabsToShow.includes(route.name) ? () => null : undefined

All credit goes to Ben Awad!

For example, if you want to have 5 active routes in a createBottomTabNavigator, but only 3 or another number to show icons in the TabBar. In this case, all 5 routes will be active, and you can go to them props.navigation.navigate()

You must pass a filtered list of routes to the TabBar component, but the object must be sure to be deeply copied (using lodash for example)

import cloneDeep from 'lodash/cloneDeep';

....

const TabBarComponent = props => {
    const routeNamesToHide = [
        'MyOfficeStack',
        'ArenaStack',
        'SavedSearchesStack',
        'NotificationsStack',
    ];
    // Delete from TABBAR items in array 'routeNamesToHide'
    let newNavigation = cloneDeep(props.navigation);
    newNavigation.state.routes = newNavigation.state.routes.filter(
        item => !routeNamesToHide.includes(item.routeName)
    );
    //
    return <BottomTabBar {...props} navigation={{ ...newNavigation }} />;
};

const tabNavigator = createBottomTabNavigator(
    {
        SearchStack,
        FavouritesStack,
        AddScreenStack,
        MessagesStack,
        BookingsStack,
        MyOfficeStack,
        AreaStack,
        SavedSearchesStack,
        NotificationsStack,
    },
    {
        lazy: false,
        tabBarOptions: {
            showLabel: true,
        },
        tabBarComponent: props => (
            <TabBarComponent {...props} />
        ),
    }
);

the easiest solution is this

        <Tab.Screen
            name='someroute'
            component={SomeComponent}
            options={{
                tabBarButton: props => null,
            }}
        />

this is by far the best solution because it doesn't require extra effort

Ben Awad solution(mentioned by Kayden van Rijn) is good, it allows centralized control, but you need extra effort to make sure the type of the route name array is correct

        <Tab.Navigator
            screenOptions={({ route }) => {
                const toExclude: typeof route.name[] = ['routeName']
                return {
                    tabBarButton: toExclude.includes(route.name)
                        ? () => {
                                return null
                          }
                        : undefined,
                }
            }}
        >

credit

Related