Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a TabNavigator with dynamic tabs

I'm relatively sure I found out it isn't possible, but I want to make sure there isn't a way.

The app in question starts off with an AppNavigator StackNavigator.

export const AppNavigator = StackNavigator({
    Login: {
        screen: Login,
        navigationOptions: ({navigation}) => ({
            title: 'Aanmelden',
            params: {
                nuke: navigation.state.params && !!navigation.state.params.nuke,
            },
        }),
    },
    Main: {
        screen: DynamicTabBar,
        navigationOptions: ({navigation}) => ({
            title: 'Follow-up',
        }),
    },
}, {
    mode: 'modal',
    headerMode: 'none',
});

export class AppWithNavigationState extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return <AppNavigator navigation={addNavigationHelpers({ dispatch: this.props.dispatch, state: this.props.navigationReducer })} />
    }
}

AppWithNavigationState.propTypes = {
    dispatch: React.PropTypes.func.isRequired,
    navigationReducer: React.PropTypes.object.isRequired,
};

const mapStateToProps = state => ({
    navigationReducer: state.navigationReducer,
});

export default connect(mapStateToProps)(AppWithNavigationState);

So far so good, it's just that the DynamicTabBar is should not be 'rendered' until the user has logged in (i.e. navigating from Login to Main).

Here's why

const Tabs = TabNavigator({
        Start: {
            screen: UserStackNavigator,
            navigationOptions: {
                tabBarIcon: (<Icon
                    type="font-awesome"
                    name="users"
                    color="#dddddd"
                    size={20}
                />),
            },
        },
        ...Account.User.CanEnter ? {
            ConditionalTab: {
                screen: ConditionalScreen,
                navigationOptions: {
                    tabBarIcon: (<Icon
                        type="font-awesome"
                        name="recycle"
                        color="#dddddd"
                        size={20}
                    />),
                },
            }} : {},
        Settings: {
            screen: Settings,
            navigationOptions: {
                tabBarIcon: (<Icon
                    type="font-awesome"
                    name="cog"
                    color="#dddddd"
                />),
            }
        }
    },{
        ...TabNavigator.Presets.AndroidTopTabs,
        tabBarPosition: "bottom",
        tabBarOptions: {
            activeTintColor: '#eaeb65',
            showIcon: true,
            showLabel: false,
            style: { backgroundColor: '#333' },
        }
    });

export default class DynamicTabBar extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        return <Tabs navigation={this.props.navigation} />;
    }
}
DynamicTabBar.router = Tabs.router;

...Account.User.CanEnter ? { is always false because the TabNavigator is rendered before the user has logged in and Account is filled. A failed attempt, it seams.

I wanted to populate Tabs inside componentWillMount, but then I can't set the static router: DynamicTabBar.router = Tabs.router;

Any ideas on how to fix this?

like image 591
DerpyNerd Avatar asked Sep 22 '17 17:09

DerpyNerd


People also ask

How do I create a custom tab in react native?

Inside the file TabNavigator/index. js , import the createBottomTabNavigator from the @react-navigation/bottom-tabs package. Using this, a Tab object is initialized. This object allows us to define the structure of the routes using the Tab.

How do I add a bottom navigation bar in react native?

To create a Bottom Tab Navigator using Material, we need to use the createMaterialBottomTabNavigator function available in the react-navigation library. It is designed with the material theme tab bar on the bottom of the screen.


1 Answers

I know this is old, but AFAICT there is no blessed way to do this still, in 2019. Here is the solution I came up with, and I think it's fairly simple.

Basically, I specify a custom tabBarComponent with a custom getButtonComponent method that either renders the button or not based on the current user. If the user shouldn't see the nav item, then it renders an empty view, which has the effect of hiding the navigation item.

import { createBottomTabNavigator } from 'react-navigation'
import { BottomTabBar } from 'react-navigation-tabs'

class TabBar extends React.Component {
  render() {
    return (
      <BottomTabBar
        {...this.props}
        getButtonComponent={this.getButtonComponent}
      />
    )
  }

  getButtonComponent({ route }) {
    if (route.key === 'Other') {
      return () => <View /> // a view that doesn't render its children
    } else {
      return null // use the default nav button component
    }
  }
}

const AppNav = createBottomTabNavigator(
  {
    Home: HomeStack,
    Other: OtherScreen,
  },
  {
    tabBarComponent: TabBar,
  }
)
like image 178
Tim Morgan Avatar answered Oct 19 '22 20:10

Tim Morgan