How can I conditionally set tabs in createBottomTabNavigator? - react-native

I have a static data file (json) that stores information like facebook page link. If the facebook page link is empty, I do NOT want the Follow Us tab to show. The facebook page link is stored in businessDataJSON.facebook. Is there a way to only show the Follow Us Tab if businessDataJSON.facebook is not empty (empty string)? This is my App.js:
const ListStack = createStackNavigator(
{
ListCategories: ListCategoriesScreen,
ListCategoryItems: ListCategoryItemsScreen
},
{
initialRouteName: "ListCategories",
defaultNavigationOptions: {
headerStyle: {
backgroundColor: businessDataJSON.theme.navigationBarBackground
},
headerTintColor: businessDataJSON.theme.navigationBarTint,
headerTitleStyle: {
fontWeight: "bold"
}
}
}
);
const FollowUsStack = createStackNavigator(
{
FollowUs: FollowUsScreen
},
{
initialRouteName: "FollowUs",
defaultNavigationOptions: {
headerStyle: {
backgroundColor: businessDataJSON.theme.navigationBarBackground
},
headerTintColor: businessDataJSON.theme.navigationBarTint,
headerTitleStyle: {
fontWeight: "bold"
}
}
}
);
export default createAppContainer(
createBottomTabNavigator(
{
ListTab: {
screen: ListStack,
navigationOptions: {
title: businessDataJSON.theme.tabBarListTitle,
tabBarIcon: ({ tintColor }) => (
<Icon
name={businessDataJSON.theme.tabBarListIcon}
size={17}
color={tintColor}
/>
)
}
},
FollowUsStack: {
screen: FollowUsStack,
navigationOptions: {
title: "Follow Us",
tabBarIcon: ({ tintColor }) => (
<Icon name="users" size={17} color={tintColor} />
)
}
}
},
{
tabBarOptions: {
activeTintColor: businessDataJSON.theme.tabBarIconActive,
inactiveTintColor: businessDataJSON.theme.tabBarIconInactive,
style: {
elevation: 8,
...Platform.select({
ios: { paddingTop: 4, paddingBottom: 4 },
android: {
borderTopWidth: 0,
paddingTop: 6,
paddingBottom: 6
}
})
}
}
}
)
);

Yes but you would need to make the creation of the tabs dinamic wich leads to the navigation prop to be lost and make a nightmare to use it without redux. The simple approach that i can see is to use a root createSwitchNavigator with a loading screen/start screen and the tabs as the 2nd screen. in the loading screen you check if there is your facebook page, and navigate to them accordingly. this example is for auth, but it works in your case . trust me, the navigation props is a nightmare to manage.

Related

React Native Navigation Title

Apparently simple problem: the Header Title in react Navigation
Navigator file with my Bottom Tabs
const BottomTabNavigator = createMaterialBottomTabNavigator(
{
ToFind: {
screen: TopBarNavigator,
navigationOptions: {
title: "Discover",
tabBarIcon: (tabInfo) => {
return (
<Ionicons
name="md-search"
size={25}
color={tabInfo.tintColor} //prende lo stesso colore di tintcolor giù
/>
);
},
tabBarColor: "#27ae60",
activeColor: "white",
},
},
....
const Navigator = createStackNavigator({
BottomTabNavigator,
Detail: DetailScreen, // not visible but I need the navigation
Item: ItemDisplay, // not visible but I need the navigation
});
Now I try to set the name into the page (at the bottom)
MapScreen.navigationOptions = (navData) => {
return {
headerTitle: "Map",
};
};
Doing this I have the Bottom Tabs styled as I want and navigation but I CAN'T change the header title (navigation title) but I always see BottomTabNavigator
It looks really trick or I'm mistaking somewhere?
Any Idea?
Thanks
createMaterialBottomTabNavigator does not have header bar by default, but createStackNavigator has.
You can do something like this.
import React from "React";
import { createAppContainer, createStackNavigator } from "react-navigation";
import { createMaterialBottomTabNavigator } from "react-navigation-material-bottom-tabs";
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Home Screen</Text>
</View>
);
}
}
const Tab1 = createStackNavigator({
S1: {
screen: ToFind
}
});
const Tab2 = createStackNavigator({
S2: {
screen: ToFind
}
});
export default createAppContainer(
createBottomTabNavigator({
Tab1,
Tab2
}, {
//CUSTOM CONFIG
initialRouteName: 'Tab1',
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ tintColor }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'Tab1') {
iconName = 'icon1';
} else if (routeName === 'Tab2') {
iconName = 'icon2';
}
return <Icon name={iconName} size={24} color={tintColor} />;
<Ionicons
name={iconName}
size={25}
color={tabInfo.tintColor} //prende lo stesso colore di tintcolor giù
/>
},
}),
tabBarOptions: {
activeTintColor: 'white',
inactiveTintColor: 'black',
showLabel: false,
style: {
backgroundColor: '#27ae60',
borderTopWidth: 0,
borderTopColor: '#27ae60',
},
},
});
);
Try these steps. Hope to fix your problem.
Create Your Bottom Tab Navigator :
const BottomTabNavigator = createMaterialBottomTabNavigator(
{
PageOne: {
screen: PageOneComponent,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <Feather name="airplay" size={26} color={tintColor} />,
tabBarLabel: null,
barStyle: { backgroundColor: 'white', elevation: 0, }
},
},
PageTwo: {
screen: PageTwoComponent,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <Feather name="search" size={25} color={tintColor}/>,
tabBarLabel: null,
barStyle: { backgroundColor: 'white', elevation: 0, }
}
},
MapViewLink: {
screen: MapView,
navigationOptions: {
tabBarIcon: <Feather name="map-pin" size={25} color={'green'} />,
tabBarOnPress: ({ navigation }) => {
navigation.navigate('MapView');
},
tabBarLabel: null
}
},
},
{
initialRouteName: 'PageOne',
activeColor: 'orange',
inactiveColor: 'grey',
labeled: false,
barStyle: { backgroundColor: 'white', elevation: 0, borderTopWidth: 1, borderTopColor: '#efefef' },
}
);
Create your StackNavigator and export the navigator
const StackNavigator = createStackNavigator({
// bottom tab navigator
BottomTabNavigator: {
screen: BottomTabNavigator,
navigationOptions: {
header: null
}
},
// MapView Page
MapView: {
screen: MapView,
navigationOptions: ({ navigation }) => ({
title: 'Hello World'
})
},
}, {
defaultNavigationOptions: ({navigation}) => ({
headerTitleAlign: 'center',
cardStyle: { backgroundColor: '#FFFFFF' },
headerTitleStyle: {
// the default styles you want to apply to header title
},
});
export default createAppContainer(StackNavigator);
In the end, put the navigator inside the main project file. e.g App.js

Share Navigation Options for Multiple Stack Navigator

Using react native with react navigation I use a DrawNavigator and several StackNavigators. Now I want to define the header style (header comes with StackNavigator) of the StackNavigator just once and for all StackNavigators.
This is what i have:
// View1.js
export default StackNav1 = createStackNavigator(
{
View1: View1Screen,
View2: View2Screen
},
{
defaultNavigationOptions: ({ navigation }) => {
return {
headerStyle: {
backgroundColor: '#9eb9b3',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
headerLeft: (
<Icon style={{ paddingLeft: 10 }} name="bars" size={30}
onPress={() => navigation.dispatch(DrawerActions.toggleDrawer())}
/>
),
}
}
}
)
// View2.js
export default StackNav2 = createStackNavigator(
{
View3: View3Screen,
View4: View4Screen
},
// here I need to define the style from View1.js again ?!
)
Is there a smarter solution to share the appearance than writing it over and over again.
When the app is scaling I probably will have a lot StackNavigators and want them to have the same header/appearance.
I appreciate your thoughts!
Create stackNavigatorConfig which is the second parameter of react navigation methods.
stackNavigatorConfig = {
defaultNavigationOptions: ({ navigation }) => {
return {
headerStyle: {
backgroundColor: '#9eb9b3'
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold'
},
headerLeft: (
<Icon
style={{ paddingLeft: 10 }}
name="bars"
size={30}
onPress={() => navigation.dispatch(DrawerActions.toggleDrawer())}
/>
)
};
}
};
Then you can use it like
export default StackNav1 = createStackNavigator({
View1: View1Screen,
View2: View2Screen
},
stackNavigatorConfig);
export default StackNav2 = createStackNavigator({
View3: View3Screen,
View4: View4Screen
},
stackNavigatorConfig);

how can I use constructor method with react navigation v3?

I need to use state on my App.js code but react-navigation v3 don't use class so I can't define the constructor method.
Is there any other way so I can use state?
I tried to use a boolean javascript variable but it didn't help.
I use StackNavigator, drawer navigator and DrawerNavigator and BottomTabNavigator like this
const TabAppNavigator = createBottomTabNavigator({
Posts: {
screen: PostsScreen,
navigationOptions: {
tabBarLabel: 'Posts',
tabBarIcon: ({ tintColor }) => (<Icon name="md-home" color={tintColor} size={25} />)
}
},
Tools: {
screen: ToolsScreen,
navigationOptions: {
tabBarLabel: 'Tools',
tabBarIcon: ({ tintColor }) => (<Icon name="md-apps" color={tintColor} size={25} />)
}
},
Favourite: {
screen: FavouriteScreen,
navigationOptions: {
tabBarLabel: 'Favourite',
tabBarIcon: ({ tintColor }) => (<Icon name="md-heart" color={tintColor} size={25} />)
}
},
}, {
initialRouteName: 'Posts',
order: ['Posts', 'Tools', 'Favourite'],
tabBarOptions: {
activeTintColor: '#d94854',
inactiveTintColor: '#818181',
style: {
backgroundColor: '#fff',
borderTopColor: '#818181',
borderTopWidth: 1,
paddingBottom: 5,
paddingTop: 15,
},
labelStyle: {
fontSize: 13,
marginTop: 10,
},
},
navigationOptions: ({ navigation }) => {
return {
headerTitle: 'Growth Hack Toolkit',
headerTintColor: '#fff',
headerStyle: {
backgroundColor: '#d94854',
},
headerLeft: (
<Icon name="md-menu" color="#fff" size={25} style={{ paddingLeft: 15 }} onPress={() => navigation.openDrawer()} />
),
headerRight: (
<Icon name="md-search" color="#fff" size={25} style={{ paddingRight: 15 }} onPress={() => search()} />
)
}
}
}
)
const PostsStackAppNavigator = createStackNavigator({
TabAppNavigator: TabAppNavigator,
Posts: { screen: PostsScreen },
Post: { screen: PostScreen }
})
const ToolsStackAppNavigator = createStackNavigator({
TabAppNavigator: TabAppNavigator,
Tools: { screen: ToolsScreen },
Tool: { screen: ToolScreen },
ToolList: { screen: ToolListScreen },
Web: { screen: WebScreen },
Mobile: { screen: MobileScreen },
})
const DrawerAppNavigator = createDrawerNavigator({
Posts: { screen: PostsStackAppNavigator },
Tools: { screen: ToolsStackAppNavigator },
About: { screen: AboutScreen },
}, {
contentComponent: SideMenu,
drawerWidth: 250,
})
const App = createAppContainer(DrawerAppNavigator);
export default App;
I want to change my header view based on my state
basically, I have a default header (the same header for all tab screens) that contains a title, menu icon to open the drawer navigation and search icon to start searching
what I need to do is that when search icon is pressed I will change my state to show the instead of the title and when close icon is pressed I will change the state to show my default header again.
after spending so much time searching for a solution or a workaround, the answer is: I cannot.
It is not possible to have state in a functional component. So I have to use react navigation v2 instead of v3 as it is implemented as class-based component.
These links could help to understand:
difference between functional and class-based React components
React State without Constructor

Drawer Navigator with Stack in React Native in Header

I have a confusion regarding React Navigation. I need a Login screen which don't have Drawer and in rest of application, I need drawer Navigation.
I am looking for a solution where I can write code in a single place and applicable on whole application.
So I have created one stack navigator which contains the path of
createStackNavigator({
LoginRT:{
screen:Login
},
HomeRT:{
screen:Home
},
ContactRT:{
screen:Contact,
navigationOptions: {
headerRight: (
<Text></Text>
)
}
},
HaulerSelectionRT:{
screen:HaulerSelection
}
},
{
initialRouteName: 'LoginRT',
/* The header config from HomeScreen is now here */
defaultNavigationOptions : ({ navigation}) => ({
headerStyle: {
backgroundColor: "#3B9EC1",
color: 'white',
fontSize: 16,
},
headerTitleStyle: {
fontWeight: 'bold',
fontSize: 20,
textAlign:"center",
flex:1
},
// headerRight: (
// <Icon
// size={30}
// name="bars"
// style={{ paddingRight: 5 }}
// onPress={() => navigation.openDrawer()}
// />
// ),
// headerLeft: <Text onPress={() =>
// navigation.navigate('LoginRT')}>Menu</Text>,
headerTintColor: "#fff",
animationEnabled: true
})
}
);
and one for Drawer Navigation
const DrawerStack = createDrawerNavigator(
{
LoginRoute: Login,
Hauler: HaulerSelection,
},
{
initialRouteName: 'LoginRoute',
drawerPosition: 'left',
// navigationOptions: {navigationOptions
// },
}
);
and then I register both in Appcontainer
const AppContainer = createAppContainer(MyRoutes,DrawerStack);
But DrawerNavigation is not working.
My doubt is, Is my approach is right? Or there is another way to achieve same.
Please help.
The header part is added by default and is avoidable.
You can use the following code to achieve this.
navigationOptions: {
header: null
}
This navigation options could either be screen specific or common to all screens.

How to navigate to a new page using navigation.navigate without the tab bar in react native

I have a tab Navigation and Navigation bar in one of the tab. I would like to navigate to the next screen. I tried out the tutorial in the https://snack.expo.io/#react-navigation/stacks-in-tabs and added this line in the code:
static navigationOptions = ({navigate, navigation}) => ({
title: "NOTIFICATION HISTORY",
headerTitleStyle: {
fontWeight: "bold",
color: Colors.tintColor,
alignSelf: "center"
},
headerStyle: {
backgroundColor: "white",
shadowOpacity: 0,
shadowOffset: {
height: 0
},
shadowRadius: 0,
borderBottomWidth: 0,
elevation: 0
}
});
export const NotiStackNavigator = StackNavigator(
{
Noti: {
screen: NotiScreen
},
NotiHistory: {
screen: NotiHistScreen
}
},
{
navigationOptions: () => ({
// gesturesEnabled: false,
headerTitleStyle: {
fontWeight: "bold",
color: Colors.tintColor,
alignSelf: "left"
},
headerStyle: {
backgroundColor: "white",
shadowOpacity: 0,
shadowOffset: {
height: 0
},
shadowRadius: 0,
borderBottomWidth: 0,
elevation: 0
}
})
}
export const MainTabNavigator = TabNavigator(
{
Home: {
screen: HomeStackNavigator
},
Noti: {
screen: NotiStackNavigator
},
Settings: {
screen: SettingsScreen
}
},
{
navigationOptions: ({ navigation }) => ({
// Set the tab bar icon
tabBarIcon: ({ focused }) => {
const { routeName } = navigation.state;
let iconName;
switch (routeName) {
case "Home":
iconName = "home";
break;
case "Noti":
iconName = "bell-o";
break;
case "Settings":
iconName = "cog";
}
return (
<FontAwesome
name={iconName}
size={24}
color={focused ? Colors.tabIconSelected : Colors.tabIconDefault}
/>
);
}
}),
// Put tab bar on bottom of screen on both platforms
tabBarComponent: TabBarBottom,
tabBarPosition: "bottom",
// Disable animation so that iOS/Android have same behaviors
animationEnabled: false,
swipeEnabled: false,
// Show the labels
tabBarOptions: {
showLabel: true,
activeTintColor: Colors.tabIconSelected,
inactiveTintColor: Colors.tabIconDefault,
style: {
backgroundColor: Colors.tabBar
}
}
}
);
I can have the tab and navigation going. When the navigation went to the next screen, the tabs still there and the name of the tab change to the new
screen's name. How do I get rid of the tab when going to the next screen?
In your details screen for your StackNavigator replace with this line :
Details: { screen: DetailsScreen, navigationOptions: { tabBarVisible: false } },
or set it as a prop for the specific screen in navigationOptions