createBottomTabNavigator can't change tab from route 3 to route 2 - react-native

I use createBottomTabNavigator in react navigation v3 and I have 3 route like that:
const Route = createBottomTabNavigator(
{
Home: {
screen: HomeRoute
}
Post: {
screen: PostRoute
},
Mark: {
screen: MarkRoute
},
}
)
but the problem or better say bug comes when I want to navigate from tab Mark to Post that doesn't navigate and change tab :(
any body can solve this problem? thanks!

For navigation, you use the navigate() function of the prop of the button you are using. For example,
If we define our createBottomTabNavigator to be,
export default createBottomTabNavigator(
{
Home: HomeScreen,
Settings: SettingsScreen,
}
);
We would move to the Settings tab using the navigate function of the button as seen below,
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
<Button
title="Go to Settings"
onPress={() => this.props.navigation.navigate('Settings')}
/>
</View>
);
}
}
Here are more detailed examples, TAB-BASED-NAVIGATION

Define your route like this
const Route = createBottomTabNavigator(
{
Home: HomeRoute,
Post: PostRoute,
Mark: MarkRoute,
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
return <View/>
},
}),
tabBarOptions: {
activeTintColor: 'red',
inactiveTintColor: 'gray'
style: {
backgroundColor: 'black'
},
labelStyle: {
fontSize: 12
},
},
}
);

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

CreateDrawerNavigator inside createStackNavigator

My issue is this: I can't seem to be able to add the hamburguer button on the left (to toggle the drawer) and also I cannot add the title to the drawer depending on the screen (for example, show 'Login' on header when it's on the login screen).
Brief explanation of the code:
The AppNavigation.js handles all the navigation for the app. Including the two drawers (LoggedDrawer and UnloggedDrawer).
They are inside a stack navigator (RootNavigator) and the RootNavigator is inside a container (react-navigation 3.0).
This is the code I have:
AppNavigation.js
const UnloggedDrawer = createDrawerNavigator(
{
Home: { screen: HomeScreen },
Login: { screen: LoginScreen },
SignUp: { screen: SignUpScreen }
}, {
drawerWidth: SCREEN_WIDTH * 0.6
}
)
const LoggedDrawer = createDrawerNavigator(
{
Home: { screen: HomeScreen },
Profile: { screen: ProfileScreen }
}, {
contentComponent: (props) => (
<View style={{ flex: 1 }}>
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
<DrawerItems {...props} />
<Button
color='red'
title='Logout'
onPress={() => { props.screenProps.logoutCurrentUser(props) }}
/>
</SafeAreaView>
</View>
),
drawerWidth: SCREEN_WIDTH * 0.6,
})
const RootNavigator = createStackNavigator({
Init: {
screen: Init,
navigationOptions: {
header: null,
},
},
UnloggedDrawer: { screen: UnloggedDrawer },
LoggedDrawer: { screen: LoggedDrawer }
},
{
mode: 'modal',
title: 'Main',
initialRouteName: 'Init',
transitionConfig: noTransitionConfig,
})
Init.js
componentWillReceiveProps(props) {
const { navigation } = props;
if (props.userReducer.isSignedUp) {
navigation.dispatch(StackActions.reset(
{ index: 0, key: null, actions: [NavigationActions.navigate({ routeName: 'LoggedDrawer' })] }
))
} else {
navigation.dispatch(StackActions.reset(
{ index: 0, key: null, actions: [NavigationActions.navigate({ routeName: 'UnloggedDrawer' })] }
))
}
}
On my screens, I have a navigationOptions for all of them just like this (the only difference is the icon), this is only part of the code just as an example:
export default class HomeScreen extends Component {
static navigationOptions = {
headerTitle: 'Home',
drawerIcon: () => (
<SimpleIcon
name="home"
color="rgba(110, 120, 170, 1)"
size={20}
/>
)};
}
So what I want to do is:
1. Add a hamburger icon to the header of all screens which will be used to toggle the drawer
2. Add the title on the middle of the header (also for all screens)
What I've tried:
Everything I could find on the internet and nothing seems to work.
Also, if my architecture is wrong, please point that out, if also there's a different way to achieve what I'm trying to do it's also accepted.
Thanks in advance. Please help.
So, answering my own question.
What I want is easily achieved by using react-native-elements.
They have a component called 'Header' that you can use on each screen to customize the header.
I added this to both of drawerNavigators and the stackNavigator.
headerMode: 'null'
Then for each screen I had to wrap the JSX code in React.Fragment, so it went like this:
<React.Fragment>
<Header
statusBarProps={{ barStyle: 'light-content' }}
barStyle="light-content"
leftComponent={
<SimpleIcon
name="menu"
color="#34495e"
size={20}
/>
}
centerComponent={{ text: 'HOME', style: { color: '#34495e' } }}
containerStyle={{
backgroundColor: 'white',
justifyContent: 'space-around',
}}
/>
</React.Fragment>
Leaving the answer in case anyone else have the same issue.

react-navigation: disable modal animation

Is it possible to disable the modal animation of React Navigation?
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
const params = navigation.state.params || {};
return {
headerLeft: (
<Button
onPress={() => navigation.navigate('MyModal')}
title="Info"
color="#fff"
/>
),
/* the rest of this config is unchanged */
};
};
/* render function, etc */
}
class ModalScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 30 }}>This is a modal!</Text>
<Button
onPress={() => this.props.navigation.goBack()}
title="Dismiss"
/>
</View>
);
}
}
const MainStack = createStackNavigator(
{
Home: {
screen: HomeScreen,
},
Details: {
screen: DetailsScreen,
},
},
{
/* Same configuration as before */
}
);
const RootStack = createStackNavigator(
{
Main: {
screen: MainStack,
},
MyModal: {
screen: ModalScreen,
},
},
{
mode: 'modal',
headerMode: 'none',
}
);
Examples are obtained from React Native official documentation: https://reactnavigation.org/docs/en/modal.html
Solution
Use transitionSpec in transitionConfig for custom screen transition. And make transition duration to Zero.
Official
Example (Not tested)
const ModalNavigator = createStackNavigator(
{
Main: { screen: Main },
Login: { screen: Login },
},
{
headerMode: 'none',
mode: 'modal',
defaultNavigationOptions: {
gesturesEnabled: false,
},
transitionConfig: () => ({
transitionSpec: {
duration: 0,
},
})
...
It's not quite what you want, but you can use the built in Modal component rendered the screen instead. The benefit of doing this is that the Modal component has an animationtype prop that you can set to "none" to get an animation-less modal.

Deep Linking in Nested Navigators in react navigation

I am using react-navigation and as per the structure of my application, we have a tab navigator inside stack navigator, I am not been able to find any proper guide for implementing Deep-Linking.
https://v1.reactnavigation.org/docs/deep-linking.html. this doesn't give any reference for nested navigators.
You have to basically pass a path to every upper route untill you come to you nested route. This is indipendent of the type of navigator you use.
const HomeStack = createStackNavigator({
Article: {
screen: ArticleScreen,
path: 'article',
},
});
const SimpleApp = createAppContainer(createBottomTabNavigator({
Home: {
screen: HomeStack,
path: 'home',
},
}));
const prefix = Platform.OS == 'android' ? 'myapp://myapp/' : 'myapp://';
const MainApp = () => <SimpleApp uriPrefix={prefix} />;
In this case to route to an inner Navigator this is the route: myapp://home/article.
This example is using react-navigation#^3.0.0, but is easy to transfer to v1.
So, after the arrival of V3 of react navigation, things got extremely stable. Now i will present you a navigation structure with deep-linking in a Switch navigator -> drawerNavigator-> tabNavigator -> stack-> navigator. Please go step by step and understand the structure and keep referring to official documentation at everystep
With nested navigators people generally mean navigation structure which consists of drawer navigator, tab navigator and stackNavigator. In V3 we have SwitchNavigator too. So let's just get to the code,
//here we will have the basic React and react native imports which depends on what you want to render
import React, { Component } from "react";
import {
Platform,
StyleSheet,
Text,
View, Animated, Easing, Image,
Button,
TouchableOpacity, TextInput, SafeAreaView, FlatList, Vibration, ActivityIndicator, PermissionsAndroid, Linking
} from "react-native";
import { createSwitchNavigator, createAppContainer, createDrawerNavigator, createBottomTabNavigator, createStackNavigator } from "react-navigation";
export default class App extends Component<Props> {
constructor() {
super()
this.state = {
isLoading: true
}
}
render() {
return <AppContainer uriPrefix={prefix} />;
}
}
class WelcomeScreen extends Component {
state = {
fadeAnim: new Animated.Value(0.2), // Initial value for opacity: 0
}
componentDidMount() {
Animated.timing( // Animate over time
this.state.fadeAnim, // The animated value to drive
{
toValue: 1,
easing: Easing.back(), // Animate to opacity: 1 (opaque)
duration: 1000,
useNativeDriver: true // Make it take a while
}
).start(); // Starts the animation
}
render() {
let { fadeAnim } = this.state;
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center", backgroundColor: '#000' }}>
<Animated.View // Special animatable View
style={{ opacity: fadeAnim }}
>
<TouchableOpacity
onPress={() => this.props.navigation.navigate("Dashboard")}
style={{
backgroundColor: "orange",
alignItems: "center",
justifyContent: "center",
height: 30,
width: 100,
borderRadius: 10,
borderColor: "#ccc",
borderWidth: 2,
marginBottom: 10
}}
>
<Text>Login</Text>
</TouchableOpacity>
</Animated.View>
<Animated.View // Special animatable View
style={{ opacity: fadeAnim }}
>
<TouchableOpacity
onPress={() => alert("buttonPressed")}
style={{
backgroundColor: "orange",
alignItems: "center",
justifyContent: "center",
height: 30,
width: 100,
borderRadius: 10,
borderColor: "#ccc",
borderWidth: 2
}}
>
<Text> Sign Up</Text>
</TouchableOpacity>
</Animated.View>
</View>
);
}
}
class Feed extends Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Button
onPress={() => this.props.navigation.navigate("DetailsScreen")}
title="Go to details"
/>
</View>
);
}
}
class Profile extends Component {
render() {
return (
<SafeAreaView style={{ flex: 1, }}>
//Somecode
</SafeAreaView>
);
}
}
class Settings extends Component {
render() {
return (
<View style={{ flex: 1 }}>
//Some code
</View>
);
}
}
const feedStack = createStackNavigator({
Feed: {
screen: Feed,
path: 'feed',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Feed",
headerLeft: (
<Icon
style={{ paddingLeft: 10 }}
name="md-menu"
size={30}
onPress={() => navigation.openDrawer()}
/>
)
};
}
},
DetailsScreen: {
screen: Detail,
path: 'details',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Details",
};
}
}
});
const profileStack = createStackNavigator({
Profile: {
screen: Profile,
path: 'profile',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Profile",
headerMode: 'Float',
headerLeft: (
<Icon
style={{ paddingLeft: 10 }}
name="md-menu"
size={30}
onPress={() => navigation.openDrawer()}
/>
)
};
}
},
DetailsScreen: {
screen: Detail,
path: 'details',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Details"
};
}
}
});
const settingStack = createStackNavigator({
Settings: {
screen: Settings,
path: 'settings',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Settings",
headerLeft: (
<Icon
style={{ paddingLeft: 10 }}
name="md-menu"
size={30}
onPress={() => navigation.openDrawer()}
/>
)
};
}
},
DetailsScreen: {
screen: Detail,
path: 'details',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Details"
};
},
}
});
const DashboardTabNavigator = createBottomTabNavigator(
{
feedStack: {
screen: feedStack,
path: 'feedStack',
navigationOptions: ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarLabel: "Feed",
tabBarVisible,
//iconName :`ios-list${focused ? '' : '-outline'}`,
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-list" color={tintColor} size={25} />
)
};
}
},
profileStack: {
screen: profileStack,
path: 'profileStack',
navigationOptions: ({ navigation, focused }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false
}
return {
tabBarVisible,
tabBarLabel: "Profile",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-man" color={tintColor} size={25} />
)
};
// focused:true,
}
},
settingStack: {
screen: settingStack,
path: 'settingsStack',
navigationOptions: ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible,
tabBarLabel: "Settings",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-options" color={tintColor} size={25} />
)
}
}
},
},
{
navigationOptions: ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
return {
// headerTitle: routeName,
header: null
};
},
tabBarOptions: {
//showLabel: true, // hide labels
activeTintColor: "orange", // active icon color
inactiveTintColor: "#586589" // inactive icon color
//activeBackgroundColor:'#32a1fe',
}
}
);
const DashboardStackNavigator = createStackNavigator(
{
DashboardTabNavigator: {
screen: DashboardTabNavigator,
path: 'dashboardtabs'
},
DetailsScreen: {
screen: Detail,
path: 'details',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Details"
};
}
}
},
{
defaultNavigationOptions: ({ navigation }) => {
return {
headerLeft: (
<Icon
style={{ paddingLeft: 10 }}
name="md-menu"
size={30}
onPress={() => navigation.openDrawer()}
/>
)
};
}
}
);
const AppDrawerNavigator = createDrawerNavigator({
Dashboard: {
screen: DashboardStackNavigator,
path: 'welcome'
},
DetailsScreen: {
screen: Detail,
path: 'friends',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Details",
};
}
}
});
//Switch navigator , will be first to load
const AppSwitchNavigator = createSwitchNavigator({
Welcome: {
screen: WelcomeScreen,
},
Dashboard: {
screen: AppDrawerNavigator,
path: 'welcome'
}
});
const prefix = 'myapp://';
const AppContainer = createAppContainer(AppSwitchNavigator);
For the process to setup React-navigation deep-linking please follow the official documentation
DetailsScreen was in my different folder and that will have class component of your choice
To launch the App the deep-link URL is myapp://welcome
To go to root page the deep-link URL is myapp://welcome/welcome
(this will reach at first page of first tab of tab navigator)
To go to any particular screen of tab navigator (suppose details
screen in profile tab) -
myapp://welcome/welcome/profileStack/details
const config = {
Tabs: {
screens: {
UserProfile: {
path: 'share//user_share/:userId',
parse: {
userId: (userId) => `${userId}`,
},
},
},
},
};
const linking = {
prefixes: ['recreative://'],
config,
};
if you have a screen in tab navigator you can do it like this via react-navigation v5

In React Native how to navigate between screens?

I am using React Navigation. I need to navigate from screen1 to screen2. I created tab navigation which include some screens but not screen1. When I click on a button from screen1 to go to screen2 which should show in tabbed screen, it is showing me error.
This is screen1(Main.js)
import React, { Component } from 'react';
import {
ImageBackground,
StyleSheet,
Text,
View,
Modal
} from 'react-native';
import { Container, Header, Left, Content, Footer, FooterTab, Icon, Grid, Row, Button } from 'native-base';
import TabNav from '../screens/Dashboard';
import { Dashboard } from '../screens/Dashboard';
export default class Main extends Component<{}> {
render() {
return (
<Container>
<Grid>
<Row size={2}>
<View style={{alignItems: 'center', flexDirection: 'column', flex: 1, justifyContent: 'space-around' }}>
<View style={{flexDirection: 'row', alignItems: 'center', justifyContent: 'center'}}>
<Button style={styles.buttonBrowseStyle} onPress={() => this.props.navigation.navigate('Dashboard')}>
<Text>Browse</Text>
</Button>
</View>
</View>
</Row>
</Grid>
</Container>
);
}
}
This is screen2(Dashboard.js)
import React from 'react';
import { Text } from 'react-native';
import { TabNavigator, TabBarBottom } from 'react-navigation';
import Post from './Post';
export const Dashboard = () => {
return (<Text>Dashboard</Text>);
}
const TabNav = TabNavigator ({
Dashboard: {
screen: Dashboard,
},
Post: {
screen: Post,
},
},
{
tabBarComponent: TabBarBottom,
tabBarPosition: 'bottom',
swipeEnabled: false,
animationEnabled: true,
activeBackgroundColor: 'yellow',
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
tabBarIcon: ({focused, tintColor}) => {
const { routeName } = navigation.state;
let iconName;
if(routeName==='Main'){
}
}
}
);
export default TabNav;
Getting this error on clicking "Browse" button.
As the above answer mentioned, you are not including Main Component to your navigation so, you can basically think like they are not connected each other whatsoever.
What I suggest you is having a PrimaryNavigator, you can think as Main component in your case.
const PrimaryNavigator = StackNavigator({
SignInStack: {
screen: SignInStackNavigator
},
SignUpStack: {
screen: SignUpStackNavigator
},
DrawerMainStack: {
screen: MenuDrawerStack
}
},
{
headerMode: 'none'
});
Next step, you can use your TabNavigator as in the below.
const MenuDrawerStack = StackNavigator({
DrawerBar: {
screen: DrawerBar
}
}, {
style: {
leftDrawerWidth: 40
},
index: 0,
navigationOptions: ({ navigation }) => ({
headerStyle: { backgroundColor: '#1874CD' },
gesturesEnabled: false,
headerLeft: <Icon
name="menu"
onPress={() => {
navigation.navigate({
key: null,
index: 0,
action: [
navigation.navigate('DrawerToggle')
]
})
}}
/>
}),
})
And finally, you can build your tab navigator :
const DrawerBar = DrawerNavigator({
Shop: {
screen: ShopTabNavigator
},
}, {
drawerPosition: 'left',
headerMode: 'none',
initialRouteName: 'Shop',
navigationOptions: ({ navigation }) => ({
headerStyle: { backgroundColor: 'white' },
}),
contentComponent: props => <CustomDrawerMenu {...props} />,
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle'
})
You should customize these but what I wanted to show you is that the methodology for navigation in React Native with react-navigation is pretty much like I showed you above.
And as the last part you have to pass PrimaryNavigator to your application as High Order Component.
export default class Main extends Component<{}> {
render() {
return (
<PrimaryNavigator />
);
}
}
Main should be part of StackNavigator. Navigation props is not available in Main because it is not a screen in any of the Navigator configuration.