props.navigation when component is not part of stack navigator - react-native

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}
/>
)
})

Related

Vue Native Drawer Navigation

Edited: Vue Native has been deprecated. So no need to answer it now
When I am using Drawer Navigator with different screens it is working fine there are 2 issues that I cannot set titles for specific screens and other is when I am on 4th screen and press back it takes me back to the home screen what supposed to do any working example that I can see?
<template>
<app-navigator></app-navigator>
</template>
<script>
import {
createAppContainer,
createStackNavigator,
createDrawerNavigator,
} from 'vue-native-router';
import Vue from 'vue-native-core';
import {VueNativeBase} from 'native-base';
Vue.use(VueNativeBase);
import LoginScreen from './screens/Login.vue';
import TenantScreen from './screens/TenantDetails.vue';
import InvoiceScreen from './screens/TenantInvoices.vue';
import PaymentScreen from './screens/PaymentHistory.vue';
import Sidebar from './screens/Sidebar/index.vue';
import React from 'react';
import {Text, View} from 'react-native';
import {DrawerItems} from 'react-navigation-drawer';
import {DrawerNavigation} from 'react-navigation';
const DrawerContent = (props) => (
<View>
<View
style={{
backgroundColor: '#224356',
height: 140,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text style={{color: 'white', fontSize: 30}}>Header</Text>
</View>
<DrawerItems {...props} />
</View>
);
const DrawerNavigator = createDrawerNavigator(
{
Login: LoginScreen,
TenantDetails: TenantScreen,
TenantInvoices: InvoiceScreen,
PaymentHistory: PaymentScreen,
},
{
initialRouteName: 'Login',
contentComponent: Sidebar,
contentOptions: {
activeTintColor: '#000000',
activeBackgroundColor: '#e6e6e6',
},
itemsContainerStyle: {
marginTop: 55,
},
},
);
const StackNavigator = createStackNavigator(
{
Drawer: DrawerNavigator,
Login: {
screen: LoginScreen,
navigationOptions: {
title: 'Login',
},
},
TenantDetails: {
screen: TenantScreen,
navigationOptions: {
headerTitle: 'Tenant Details',
},
},
TenantInvoices: {
screen: InvoiceScreen,
navigationOptions: {
headerTitle: 'Tenant Invoices',
},
},
PaymentHistory: {
screen: PaymentScreen,
navigationOptions: {
headerTitle: 'Payment History',
},
},
},
{
headerMode: 'none',
},
);
const AppNavigator = createAppContainer(StackNavigator);
export default {
components: {AppNavigator},
};
</script>

Nested Stack Navigator and Drawer Navigator in React Native

I have a couple of issues with setup Stack Navigator and Drawer Navigator. First and foremost, the below picture is the flow that I expected and I followed the documentation provided by the React Navigation to implement but I have no luck to achieve what I expected and the output of the implementation looks so weird (You can find it on the 2nd picture). I also attached my code snippet at the bottom.
Also, the output looks like the Drawer navigator header is duplicated with the Stack Navigator.
Besides that, I am quite new to React Native. I hope someone makes me more clearer how the implementation should look like because I have come across few articles and websites, their solution does not work in my case.
P/S: Screen X is opened when one of item clicked from Screen C
import React, { Component } from 'react';
import {
Image,
Button,
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
} from 'react-native';
import { createDrawerNavigator, DrawerActions, DrawerItems } from 'react-navigation-drawer';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import HomeScreen from '../HomeScreen';
import ItemDetailScreen from '../ItemDetailScreen';
import ProfileScreen from '../ProfileScreen';
const navOptionsHandler = (navigation) => {
header: null
}
const CustomDrawerComponent = (props) => (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ height: 150, backgroundColor: 'white', alignItems: 'center' }}>
<Image source={{ uri: 'https://example.com/logo.png' }} style={{
height: 120,
width: 120,
borderRadius: 60
}} />
</View>
<ScrollView>
<DrawerItems {...props} />
</ScrollView>
</SafeAreaView>
)
const MyDrawerNavigator = createDrawerNavigator(
{
Home: {
screen: HomeScreen
},
Profile: {
screen: ProfileScreen
}
},
{
initialRouteName: "Home",
contentComponent: CustomDrawerComponent,
contentOptions: {
activeTintColor: 'orange'
}
}
);
const MyStackNavigator = createStackNavigator(
{
HomeA: {
screen: MyDrawerNavigator
},
ItemDetail: {
screen: ItemDetailScreen,
navigationOptions: navOptionsHandler
}
},
{
initialRouteName: "HomeA"
}
);
const AppContainer = createAppContainer(MyStackNavigator);
export default class StackNavigator extends Component {
render() {
return <AppContainer />;
}
}
Your drawer navigator is encapsulated by the stack navigator, which is why you have a double header.
What you need to do is to have the drawer navigator as your main navigator, and have your stack navigator as your profile screen, so it will be displayed as you click on "Profile" in your drawer navigator.
This should work:
const navOptionsHandler = navigation => {
null
}
const CustomDrawerComponent = props => (
<SafeAreaView style={{ flex: 1 }}>
<View
style={{ height: 150, backgroundColor: 'white', alignItems: 'center' }}
>
<Image
source={{ uri: 'https://example.com/logo.png' }}
style={{
height: 120,
width: 120,
borderRadius: 60,
}}
/>
</View>
<ScrollView>
<DrawerItems {...props} />
</ScrollView>
</SafeAreaView>
)
const MyStackNavigator = createStackNavigator(
{
Profile: ProfileScreen,
ItemDetail: {
screen: ItemDetailScreen,
navigationOptions: navOptionsHandler,
},
},
{
initialRouteName: 'Profile',
},
)
const MyDrawerNavigator = createDrawerNavigator(
{
Home: HomeScreen,
ProfileStack: {
screen: MyStackNavigator,
navigationOptions: () => ({
title: 'Profile',
}),
}
},
{
initialRouteName: 'Home',
contentComponent: CustomDrawerComponent,
contentOptions: {
activeTintColor: 'orange',
},
},
)
const AppContainer = createAppContainer(MyDrawerNavigator)
export default class StackNavigator extends Component {
render() {
return <AppContainer />
}
}
By the way since you say you are only just starting using React Native, unless you have a specific reason to use React Navigation v4, you should probably use v5 instead as v4 will become obsolete one day or another.

How to go back by backButton in stack navigator that is inside drawer navigator

I have a multiple screens that every which is a stackNavigator.
any created stackNavigator is inside drawer.
in every screen , when press BackButton of stackNavigator's header, screen
navigate to initialRoute always instead back to last screen.
I tested navigation.goBack() and navigation.goBack(null) and
navigation.goBack() and navigation.goBack(this.props.navigation.state.key)}
but none of these worked.
here is my code:
const MenuScreenNavigator = createStackNavigator({
Menu: {
screen: MenuScreen,
navigationOptions: ({ navigation }) => ({
headerLeft: (
<HeaderBackButton
tintColor="white"
onPress={() => navigation.goBack()}
/>
)
}
i have multiple screen navigator such as Menu navigator: "Load", "Home",... screens.
in continue i have drawer navigator:
const drawerConfig = {
drawerPosition: 'right',
contentComponent: CustomDrawerContent,
initialRouteName: "Load"
}
const routeConfig = {
Menu: {
screen: MenuScreenNavigator,
navigationOptions: { title: strings.screenName.menu }
},
Load: { screen: AuthLoadingScreenNavigator },
Login: {
screen: LoginScreenNavigator,
navigationOptions: {
drawerLabel: () => null
}
},
User: { screen: UserScreenNavigator }
}
and then i create drawerNavigator:
const DrawerNavigator = createDrawerNavigator(routeConfig, drawerConfig)
export default createAppContainer(DrawerNavigator)
Drawer Navigation
This navigation method provides a way to directly switch between different screens via a drawer. This slide drawer contains links to different screens of the application.
Stack Navigation
This kind of navigator provides a way to transition between screens and manage navigation history. When clicking on a button or a link, a new screen is put on top of the old screen. It is something like push on pop of a stack. User able to go back to the previous screens one by one from the back button.
So to be able to navigate back you at least have to put a screen over another one, so on your initial pages that you navigated using your drawer you won't be able to go back.
Taking the example above you can't go back from screen1 to user, or from screen2 to menu. You have to follow the stack navigator flow. For example:
Menu > screen1 > screen4
then you can go back
screen4 > screen1 > Menu
Now let's jump to a real example taking the above diagram:
App.js
import React, { Component } from 'react';
import { View, Text, TouchableHighlight, Image } from 'react-native';
import { DrawerNavigator, createStackNavigator } from 'react-navigation';
import Menu from './pages/Menu/Menu';
import Screen1 from './pages/Menu/Screen1';
import Screen4 from './pages/Menu/Screen4';
import User from './pages/User/User';
import Screen2 from './pages/User/Screen2';
import Screen5 from './pages/User/Screen5';
import Login from './pages/Login/Login';
import Screen3 from './pages/Login/Screen3';
import Screen6 from './pages/Login/Screen6';
const MenuStack = createStackNavigator(
{
Menu: {
screen: Menu,
navigationOptions: {
header: null,
},
},
Screen1: {
screen: Screen1,
},
Screen4: {
screen: Screen4,
},
},
{
initialRouteName: 'Menu',
}
);
const UserStack = createStackNavigator(
{
User: {
screen: User,
navigationOptions: {
header: null,
},
},
Screen2: {
screen: Screen2,
},
Screen5: {
screen: Screen5,
},
},
{
initialRouteName: 'User',
}
);
const LoginStack = createStackNavigator(
{
Login: {
screen: Login,
navigationOptions: {
header: null,
},
},
Screen3: {
screen: Screen3,
},
Screen6: {
screen: Screen6,
},
},
{
initialRouteName: 'Login',
}
);
export default DrawerNavigator(
{
Menu: {
screen: MenuStack,
},
Info: {
screen: UserStack,
},
Login: {
screen: LoginStack,
},
},
{
initialRouteName: 'Menu',
}
);
Menu.js, User.js, Login.js
import React, { Component } from 'react';
import { View, Text, Button } from 'react-native';
import Header from '../../Header';
export default class MenuScreen extends Component {
render() {
return (
<View
style={{
flex: 1,
flexDirection: 'column',
}}>
<Header {...this.props} />
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text style={{ fontWeight: 'bold', fontSize: 22 }}>
This is Menu Screen
</Text>
<Button
title="Go to Screen1"
onPress={() => this.props.navigation.navigate('Screen1')}
/>
</View>
</View>
);
}
}
Screen1.js, Screen2.js, Screen3.js
import React, { Component } from 'react';
import { View, Text, Button } from 'react-native';
export default class Screen2 extends Component {
render() {
return (
<View
style={{
flex: 1,
flexDirection: 'column',
}}>
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text style={{ fontWeight: 'bold', fontSize: 22 }}>
This is Screen2
</Text>
<Button
title="Go to Screen5"
onPress={() => this.props.navigation.navigate('Screen5')}
/>
<Button
title="Go to Back"
onPress={() => this.props.navigation.goBack()}
/>
</View>
</View>
);
}
}
Screen4.js, Screen5.js, Screen6.js
import React, { Component } from 'react';
import { View, Text, Button } from 'react-native';
export default class Screen4 extends Component {
render() {
return (
<View
style={{
flex: 1,
flexDirection: 'column',
}}>
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text style={{ fontWeight: 'bold', fontSize: 22 }}>
This is Screen4
</Text>
<Button
title="Go to Back"
onPress={() => this.props.navigation.goBack()}
/>
</View>
</View>
);
}
}
Check out the source code: snack.expo.io/#abranhe/react-navigation.
Hmm, maybe try this, or one of the other solutions proposed in that discussion, see if that solves your problem.

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>
);
}
};

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.