Search code examples
react-nativenestedreact-navigationtabnavigator

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?


Solution

  • Yessssss! I think I found a way. The solution probably isn't following the design pattern, but this is what I came up with:

    export default class DynamicTabBar extends React.Component {
        static router = TabRouter({
            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' },
            }
        });
        constructor(props) {
            super(props);
        }
    
        render() {
            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' },
                }
            });
    
            return <Tabs navigation={this.props.navigation} />;
        }
    }
    

    The router is assigned in a static way and is built dynamically at runtime.