In React Native how to navigate between screens? - react-native

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.

Related

React Navigation - undefined is not an object (evaluating 'this.navigation.navigate')

I am following this tutorial to implement a switch navigator for user authentication: https://snack.expo.io/#react-navigation/auth-flow-v3.
However, this.navigation.navigate appears to undefined when I try to navigate to the next screen.
undefined is not an object (evaluating 'this.props.navigation.navigate')
I am using expo for my app, and I've already looked at the solutions posted to a similar question at React Native - navigation issue "undefined is not an object (this.props.navigation.navigate)" to no avail.
import * as React from 'react';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import profile from './app/screens/profile.js'
import home from './app/screens/home.js'
import createCompetition from './app/screens/create.js'
import explore from './app/screens/explore.js'
import Icon from 'react-native-vector-icons/MaterialIcons'
import login from './app/screens/login.js';
import { f } from './config/config.js';
import { ActivityIndicator, AsyncStorage, Button, StatusBar, StyleSheet, View } from 'react-native';
import { createStackNavigator } from 'react-navigation-stack';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
/**
* Tab Stack is the Bottom Navigator for the different pages
*/
const TabStack = createBottomTabNavigator(
{
Home: {
screen: home,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Icon name="home" size={25} style={{ color: tintColor }} />
),
},
},
Explore: {
screen: explore,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Icon name="search" size={25} style={{ color: tintColor }} />
),
}
},
Profile: {
screen: profile,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Icon name="person" size={25} style={{ color: tintColor }} />
),
}
},
Create: {
screen: createCompetition,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Icon name="add" size={25} style={{ color: tintColor }} />
),
}
},
},
{
tabBarOptions: {
showIcon: true,
showLabel: false,
activeTintColor: 'black',
style: { backgroundColor: 'white', }
},
},
)
/**
* Loading Screen during authorization process
*/
class AuthLoadingScreen extends React.Component {
constructor() {
super();
this._bootstrapAsync();
}
// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = async () => {
f.auth().onAuthStateChanged(function (user) { //checks if user is signed in or out
this.props.navigation.navigate(user ? 'App' : 'Auth');
})
};
// Render any loading content that you like here
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
const AppStack = createStackNavigator({ Home: TabStack });
const AuthStack = createStackNavigator({ Login: login });
const RootStack = createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: AppStack,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
);
const App = createAppContainer(RootStack);
export default App;
You are not giving access to this to your _bootstrapAsync function and your onAuthStateChanged callback. Just pass the callback inside of it using arrow function, as it autobinds the current function to the current app this
_bootstrapAsync = async () => {
f.auth().onAuthStateChanged((user) => { //checks if user is signed in or out
this.props.navigation.navigate(user ? 'App' : 'Auth');
})
};
The problem is with function keyword, which doesnt bind this keyword. Better replace it with ES6 arrow functions which implictly binds this to the inner scope :
f.auth().onAuthStateChanged((user) => { //checks if user is signed in or out
this.props.navigation.navigate(user ? 'App' : 'Auth');
})
Hope it helps .feel free for doubts

props.navigation when component is not part of stack navigator

I have a stackNavigator and DrawerNavigator defined in AppNavigator.js file. It is then imported by App. In AppNavigator, I have a drawer icon to open the sidebar but I can't open it yet because navigate don't exist. I can't pass navigation to AppNavigator sine App component is not part of the stack navigator. I am trying to contain my navigation in one file and still be able to open/close my drawer bar from there. Any help?
AppNavigator.js:
import React from 'react';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import ScreenHome from './screens/member/ScreenHome';
import { createDrawerNavigator } from 'react-navigation-drawer';
import Icon from "react-native-vector-icons/Ionicons";
const authenicatedNavigation = createStackNavigator(
{
Home: {
screen: ScreenHome,
navigationOptions: ({ navigation }) => ({
title: "Home",
drawerLabel: "Home"
})
}
},
{
initialRouteName: "Home",
headerMode: "screen",
defaultNavigationOptions: {
headerStyle: {
backgroundColor: '#ffffff',
elevation: 0,
shadowOpacity: 0
},
headerTintColor: '#333333',
headerTitleStyle: {
fontWeight: 'bold',
color: '#ffffff'
},
headerLeft: (
<Icon
style={{paddingLeft: 10, color:'white'}}
onPress={()=> navigation.openDrawer()} //-----undefined navigation
name="md-menu"
size={30}
/>
)
}
}
)
const MainDrawer = createDrawerNavigator(
{
MainTabs: authenicatedNavigation,
},
{
hideStatusBar : false,
drawerBackgroundColor: 'rgba(255,255,255,0)',
overlayColor : '#f68873',
contentOptions: {
activeTintColor: '#fff',
activeBackgroundColor: '#6b52ae'
}
}
);
const App = createSwitchNavigator({
App: {
screen: MainDrawer,
}
});
const AppNavContainer = createAppContainer(
App,
{
initialRouteName: 'App',
}
);
export default AppNavContainer;
App.js:
import React , {Component} from 'react';
import { StyleSheet, View } from 'react-native';
import AppNavContainer from './AppNavigator';
import NavigationService from './shared/NavigationService';
import {axios} from './shared/httpinterceptor';
export default class App extends Component {
constructor(){
super();
}
render() {
return (
<View>
<AppNavContainer
ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}}
/>
</View>
);
}
}
Currently, in ScreenHome file, I can open the drawer by:
<Button onPress={this.props.navigation.openDrawer} title="Open"/>
Given I have no access to props.navigation in Apps, how do I open the drawer from AppNavigator?
defaultNavigationOptions (as well as navigationOptions) can be defined as a function which receives the navigation instance as parameter, so you'd just need to update your defaultNavigationOptions as follows:
defaultNavigationOptions: ({navigation}) => ({
headerStyle: {
backgroundColor: '#ffffff',
elevation: 0,
shadowOpacity: 0
},
headerTintColor: '#333333',
headerTitleStyle: {
fontWeight: 'bold',
color: '#ffffff'
},
headerLeft: (
<Icon
style={{paddingLeft: 10, color:'white'}}
onPress={()=> navigation.openDrawer()}
name="md-menu"
size={30}
/>
)
})

How to make sure a Drawer Navigation is completely removed when I navigate to another BottomTabNavigator?

I have a BottomTabNavigator which, contains another BottomTabNavigator and two DrawerNavigator s.
One of the DrawerNavigators represents the authenticated state. I just implemented a log out button in this drawerNavigation. The button purges the redux state and navigates to the BottomTabNavigator, more specifically, to the Login route of the Welcome navigator.
However, once in the Welcome Navigato after logout, the authenticated Drawer shows up when I try to navigate to another route of the BottomTabNavigator.
I am not sure why this is happening. When I refresh the expo project, I realize that indeed the application is in a non-authenticated state.
Is there a way to make sure the Authenticated Drawer Navigator does not show up when I log out ?
Here is my main navigator:
import React, { Component } from 'react';
import {
AppRegistry,
View,
SafeAreaView,
Button,
AsyncStorage,
TouchableOpacity,
Text,
} from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import { PersistGate } from 'redux-persist/integration/react';
import {
createBottomTabNavigator,
createSwitchNavigator,
createDrawerNavigator,
createStackNavigator,
DrawerItems,
} from 'react-navigation';
import { Provider } from 'react-redux';
import Welcome from './screens/Welcome';
import Register from './screens/RegisterScreen';
import Login from './screens/LoginScreen';
import Home from './screens/Home';
import Events from './screens/Events';
import Board from './screens/Board';
import HomePage from './screens/HomePage';
import SettingsScreen from './screens/BusinessSettings';
import BusinessEvents from './screens/BusinessEvents';
import EventListings from './screens/EventListings';
import BusinessListings from './screens/BusinessListings';
import Business from './screens/Business';
import BusinessForm from './screens/BusinessForm';
import EventForm from './screens/EventForm';
import Logout from './screens/Logout';
import { persistor, store } from './store';
const MainNavigator = createBottomTabNavigator(
{
Welcome: createBottomTabNavigator({
Welcome: Welcome,
Login: Login,
Register: Register,
Board: Board,
}),
Home: createDrawerNavigator({
Home: {
screen: Home,
},
Events: {
screen: Events,
},
Business: {
screen: Business
}
}),
HomePage: createDrawerNavigator({
HomePage: {
screen: HomePage,
},
Settings: {
screen: SettingsScreen,
},
EventListings: {
screen: EventListings
},
EventForm: {
screen: EventForm
},
BusinessEvents: {
screen: BusinessEvents
},
BusinessListings: {
screen: BusinessListings
},
NewBusiness: {
screen: BusinessForm
},
Business: {
screen: Business
}
}, {
contentComponent: (props) => (
<View style={{ flex:1 }}>
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
<DrawerItems {...props} />
<TouchableOpacity style={{ flexDirection: 'row', marginLeft: '8%', paddingTop: '2%' }} onPress={ async () => {
await AsyncStorage.clear();
await persistor.purge();
props.navigation.navigate("Welcome");
}}>
<Ionicons name="ios-log-out-outline" size={24} color="#053541" /><Text style={{ marginLeft: '14%', fontWeight: 'bold', color: 'black' }}>Log Out</Text>
</TouchableOpacity>
</SafeAreaView>
</View>
),
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle'
})
},
{
headerMode: 'none',
navigationOptions: {
header: null,
tabBarVisible: false,
headerVisible: false,
headerMode: 'none',
},
tabBarVisible: false,
swipeEnabled: false,
animationEnabled: false,
lazy: true,
transitionConfig: () => ({
transitionSpec: {
duration: 0,
},
}),
/* Other configuration remains unchanged */
}
);
export default class App extends Component {
render() {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<MainNavigator />
</PersistGate>
</Provider>
);
}
};

How can TabNavigator child screen refer to parent StackNavigator?

The structure of the application is this.
StackNavigator
StackA-Screen(TabNavigator)
TabChildA-Screen
TabChildB-Screen
...
StackB-Screen
code in App.js
const TabComponent = TabNavigator(
{
TabChildA-Screen: {
screen: TabChildA,
},
TabChildB-Screen: {
screen: TabChildB,
}
},
{
tabBarPosition: "bottom",
animationEnabled: false,
swipeEnabled: false
}
);
const StackComponent = StackNavigator(
{
StackA-Screen: {
screen: TabComponent,
navigationOptions: ({ navigation }) => ({
headerBackTitle: null,
headerRight: (
<TouchableWithoutFeedback
onPress={() =>
navigation.navigate("StackB-Screen", { space: "" }) // can't navigate to "StackB-Screen".
}
>
<MaterialIcon
name="playlist-add"
size={Sizes.NavigationBar.Icon.Size}
style={{ padding: 8, color: Colors.White }}
/>
</TouchableWithoutFeedback>
)
})
},
StackB-Screen: {
screen: StackB,
}
},
{
initialRouteName: "StackA-Screen",
mode: "modal"
}
);
export default StackComponent;
I want to navigate TabChildA-Screen to StackB-Screen.
But, TabChildA-Screen can refer to navigator is navigator of TabNavigator.
code in TabChildA-Screen
import React, { Component } from "react";
import { Button, Text, View } from "react-native";
class StackB extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center"
}}
>
<Button
onPress={ () =>
this.props.navigation.navigate("StackB-Screen") // can't navigate to "StackB-Screen".
}
title="move to StackB-Screen"
/>
</View>
);
}
}
export default StackB;
How to TabChildA-Screenrefer StackNavigator ?

How to start Tab Navigation after Onboarding Screen?

i have the following problem:
I am currently working on a app with react native.
I use 'react-navigation' for the navigation. Now i want to setup an Onboarding Screen, which is only shown at the first start of my application.
This screen should be shown in fullscreen format, nav bar and the tab bar should't be visible.
I already implemented the logic with AsyncStorage, for the Screen itself i use 'react-native-app-intro-slider'.
But how can i set it to be the initial screen? I was able to show it in my very first tab after initial launch of the screen, but then the tab bar is shown as well.
I could potentially hide the tabbar, but after completing the onboarding setup/screen I want the tab bar to be visible again.
Is there a way to show the screen fullscreen and after completing the onboarding to navigate to the Tab Navigator?
I am very new to react native and also javascript in general, sorry if this question is unprecise.
App.
App.js:
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
Button,
ScrollView,
Statusbar
} from 'react-native';
import { SafeAreaView, TabNavigator, StackNavigator } from 'react-navigation';
import Home from './Tabs/Home';
import Wheel from './Tabs/Wheel';
import Categories from './Tabs/Categories';
import Settings from './Tabs/Settings';
import TabBar from './Tabs/TabBar';
import StrafenScreen from './screens/StrafenScreen';
import VideoScreen from './screens/VideoScreen';
import UberUns from './screens/UberUns';
import Rechtliches from './screens/Rechtliches';
import SprachAuswahl from './screens/Sprachauswahl';
import RandomVideoScreen from './screens/RandomVideoScreen';
import Onboarding from './screens/Onboarding.js';
export const FeedStack = StackNavigator({
Category: {
screen: Categories,
navigationOptions: {
title: 'Kategorien',
},
},
Strafen: {
screen: StrafenScreen,
navigationOptions: ({ navigation }) => ({
title: `${navigation.state.params.key} `,
}),
},
Videos: {
screen: VideoScreen,
navigationOptions: ({ navigation }) => ({
tabBarVisible: (navigation.state.params && navigation.state.params.hideTabBar) === true,
title: `${navigation.state.params.key} `,
}),
},
});
export const WheelStack = StackNavigator({
Wheel: {
screen: Wheel,
navigationOptions: {
title: 'Glücksrad',
},
},
RandomVideo: {
screen: RandomVideoScreen,
navigationOptions: ({ navigation }) => ({
tabBarVisible: (navigation.state.params && navigation.state.params.hideTabBar) === true,
animationEnabled: true
}),
},
Onboarding: {
screen: Onboarding,
navigationOptions: ({ navigation }) => ({
tabBarVisible: (navigation.state.params && navigation.state.params.hideTabBar) === true,
animationEnabled: true
}),
},
});
export const SettingsStack = StackNavigator({
Settings: {
screen: Settings,
navigationOptions: {
title: 'Über uns',
},
},
UberUns: {
screen: UberUns,
navigationOptions: ({ navigation }) => ({
title: `${navigation.state.params.key} `,
}),
},
SprachAuswahl: {
screen: SprachAuswahl,
navigationOptions: ({ navigation }) => ({
title: `${navigation.state.params.key} `,
}),
},
Rechtliches: {
screen: Rechtliches,
navigationOptions: ({ navigation }) => ({
title: `${navigation.state.params.key} `,
}),
},
});
const MainScreenNavigator = TabNavigator({
Home: {screen: Home},
Kategorien: {screen: FeedStack},
Rad: {screen: WheelStack},
Einstellungen: {screen: SettingsStack}
},
{
swipeEnabled:true,
tabBarOptions: {
activeTintColor: 'white',
activeBackgroundColor: 'darkgrey',
inactiveTintColor: 'black',
inactiveBackgroundColor: 'grey',
labelStyle: {
fontSize: 11,
padding: 0
}
}
});
MainScreenNavigator.navigationsOptions = {
title: 'Demo'
};
StackNavigator.navigationOptions = {
headerStyle: {
borderBottomWidth: 0,
}
};
export default MainScreenNavigator;
My First Tab:
import React from 'react';
import {
Text,
View,
Button,
Image,
TouchableHighlight,
TouchableOpacity,
AsyncStorage
} from 'react-native';
import WelcomeScreen from '../screens/WelcomeScreen.js';
import Onboarding from '../screens/Onboarding.js';
import checkIfFirstLaunch from '../components/checkLaunch';
export default class Home extends React.Component {
static navigationOptions = {
tabBarLabel: 'Home',
tabBarIcon: ({tintColor}) => (
<Image
source={require('../images/home.png')}
style={{width: 22, height: 22, tintColor: 'white'}}>
</Image>
)
}
constructor(props) {
super(props);
this.state = {
isFirstLaunch: false,
hasCheckedAsyncStorage: false,
};
}
async componentWillMount() {
const isFirstLaunch = await checkIfFirstLaunch();
this.setState({ isFirstLaunch, hasCheckedAsyncStorage: true });
}
render() {
const { hasCheckedAsyncStorage, isFirstLaunch } = this.state;
const { navigate } = this.props.navigation;
if (!hasCheckedAsyncStorage) {
return null;
}
return isFirstLaunch ?
<Onboarding /> :
<View style={styles.container}>
<TouchableOpacity
style={{ flex: 1,
alignItems: 'center',
justifyContent: 'center', }}
onPress={
() => navigate('Kategorien', {})
}
>
<Image
style={{ width: 230, height: 230, borderWidth: 3, marginTop: 30}}
source={require('../images/final-course-categories.jpg')}
>
</Image>
</TouchableOpacity>
<TouchableOpacity
style={{ flex: 1,
alignItems: 'center',
justifyContent: 'center', }}
onPress={
() => navigate('Rad', {})
}
>
<Image
style={{ width: 230, height: 230, borderWidth: 3}}
source={require('../images/fortuneWheel.png')}
>
</Image>
</TouchableOpacity>
</View>
;
}
}
const styles = {
container: {
flex: 1,
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
},
buttonContainer: {
flex: 1
}
};
Onboarding component:
import React from 'react';
import { StyleSheet } from 'react-native';
import AppIntroSlider from 'react-native-app-intro-slider';
const styles = StyleSheet.create({
image: {
width: 100,
height: 100,
}
});
const slides = [
{
key: 'somethun',
title: 'Achtung',
text: 'Die Strafen in dieser App sind nur als Spaß gedacht.\nBitte nicht ernst nehmen.',
image: require('../images/warning.png'),
imageStyle: styles.image,
backgroundColor: '#59b2ab',
},
{
key: 'somethun-do',
title: 'Title 2',
text: 'Other cool stuff',
backgroundColor: '#febe29',
},
{
key: 'somethun1',
title: 'Rocket guy',
text: 'Lorem ipsum',
image: require('../images/home.png'),
imageStyle: styles.image,
backgroundColor: '#22bcb5',
}
];
export default class App extends React.Component {
_onDone = () => {
}
static navigatorStyle = {
navBarHidden: true
};
render() {
return (
<AppIntroSlider
slides={slides}
onDone={this._onDone}
/>
);
}
}
How can i even tell my App which screen it should use as the initial screen?
Thanks.