Expo React Native Drawer Navigator Logout functionality - javascript

StackOverflow I am very new to react native since I implement drawer navigation now I want to include a logout button at the end of the drawer but I don't find how to do that any good practice and ideas about how to achieve this kind of functionality. this is my code for drawer I find it from hours of google and it works fine but it has functions of screens I don't find any option of how to make a logout link in this code if this code is not correct then suggest any other good snippet thanks in advance
import React from 'react';
import { Ionicons } from '#expo/vector-icons'
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import { createDrawerNavigator, createStackNavigator, createAppContainer } from 'react-navigation';
import { DrawerActions } from 'react-navigation-drawer';
// _signOutAsync = async () => {
// await AsyncStorage.clear();
// this.props.navigation.navigate('Auth');
// };
const HomeScreen = () => (
<View style={styles.container}>
<Text>Home Screen!</Text>
</View>
);
const ProfileScreen = () => (
<View style={styles.container}>
<Text>Profile Screen!</Text>
</View>
);
const SettingsScreen = () => (
<View style={styles.container}>
<Text>Settings Screen!</Text>
</View>
);
const DrawerNavigator = createDrawerNavigator({
Home: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => ({
title: 'Home Screen',
drawerLabel: 'Home',
drawerIcon: () => (
<Ionicons name="ios-home" size={20} />
)
})
},
Profile: {
screen: ProfileScreen,
navigationOptions: ({ navigation }) => ({
title: 'Profile Screen',
drawerLabel: 'Profile',
drawerIcon: () => (
<Ionicons name="ios-person" size={20} />
)
})
},
Settings: {
screen: SettingsScreen,
navigationOptions: ({ navigation }) => ({
drawerIcon: () => (
<Ionicons name="ios-settings" size={20} />
)
})
},
});
const StackNavigator = createStackNavigator({
DrawerNavigator: {
screen: DrawerNavigator,
navigationOptions: ({ navigation }) => {
const { state } = navigation;
if(state.isDrawerOpen) {
return {
headerLeft: ({titleStyle}) => (
<TouchableOpacity onPress={() => {navigation.dispatch(DrawerActions.toggleDrawer())}}>
<Ionicons name="ios-close" style={styles.menuClose} size={36} color={titleStyle} />
</TouchableOpacity>
),
}
}
else {
return {
headerLeft: ({titleStyle}) => (
<TouchableOpacity onPress={() => {navigation.dispatch(DrawerActions.toggleDrawer())}}>
<Ionicons name="ios-menu" style={styles.menuOpen} size={32} color={titleStyle} />
</TouchableOpacity>
),
}
}
}
}
})
export default createAppContainer(StackNavigator);

You can create one content component to render inside your Drawer Navigator, making it easier to modify.
I will explain with your example (I am assuming that it is your App.js file):
//import CustomDrawer from '...'
const DrawerNavigator = createDrawerNavigator({
Home: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => ({
title: 'Home Screen',
drawerLabel: 'Home',
drawerIcon: () => (
<Ionicons name="ios-home" size={20} />
)
})
},
Profile: {
screen: ProfileScreen,
navigationOptions: ({ navigation }) => ({
title: 'Profile Screen',
drawerLabel: 'Profile',
drawerIcon: () => (
<Ionicons name="ios-person" size={20} />
)
})
},
Settings: {
screen: SettingsScreen,
navigationOptions: ({ navigation }) => ({
drawerIcon: () => (
<Ionicons name="ios-settings" size={20} />
)
})
},
//Here you will add one more pair of curly brackets to add more configs.
}, {
initialRouteName: 'Home',
contentComponent: CustomDrawer //This is the option that will allow you to add the button
});
You will create one entire component to modify like you want and then render inside the Drawer Navigator. Remember, I am using CustomDrawer name, you will import this component inside your App.js file.
import React from 'react';
import { View, Text, Image, StyleSheet } from 'react-native';
import { Button } from 'react-native-elements';
import { DrawerNavigatorItems } from 'react-navigation-drawer';
const CustomDrawer = ({ ...props }) => {
return (
<>
<View>
<DrawerNavigatorItems
{...props}
itemsContainerStyle={{}}
itemStyle={{}}
/>
</View>
<View
style={{
flexDirection: 'row',
alignSelf: 'center',
position: 'relative',
marginBottom: 20,
}}
>
<Button
title={'Log out'}
buttonStyle={{ width: 200, borderRadius: 20 }}
onPress={}
/>
</View>
</>
);
};
const styles = StyleSheet.create({});
export default CustomDrawer;
Here I am rendering only the CustomDrawer props, that is the itens that you create in your App.js and rendering it (specifically it is the ...props that I am passing in DrawerNavigationItems, so you can customize it like you want, like one normal screen, place buttons, create views and apply styles to it.
You can also instead of creating one new screen to render inside your Drawer Navigator code it inside your App.js, but personally I feel it much messed up
You can learn more with this tutorial

Related

Open Navigation Drawer On Header Button Click

when i swipe right my drawer open but i want to open it using a button in the header i did a code but i have this error undefined is not a object (evaluating 'navigation.openDrawer')
thats my app.js code :
import {createStackNavigator} from 'react-navigation-stack';
import { createAppContainer } from 'react-navigation';
import Home from './components/login'
import Inscription from './components/inscription'
import signup from './components/signup'
import mp from './components/motdepasse'
import ch from './components/choice'
import mn from './components/menu1'
import drawer from './components/drawerapp'
import React, { Component } from 'react';
import { Image, StyleSheet, Text, TouchableOpacity, } from 'react-native';
import Icon from 'react-native-vector-icons/Entypo'
const Navigator = createStackNavigator({
Home:{screen: Home},
Profil:{screen: Inscription},
signup:{screen: signup, navigationOptions: { header: null }},
mp:{screen: mp},
ch:{screen: ch},
mn:{screen: mn},
drawer:{screen: drawer,navigationOptions: { title:"votre travail",
headerStyle:{backgroundColor:'#8B0000'},
headerTitleStyle: {
fontWeight: 'bold',
color:'white',
},
headerLeft: ({ navigation }) => (
<TouchableOpacity onPress={() => navigation.openDrawer()} >
<Icon name={'menu'} size={28} color={'white'} style={{marginRight:10}}/>
</TouchableOpacity>
),}},
}
);
const App = createAppContainer(Navigator);
export default App;
and that's my appdrawer code:
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem label="Help" onPress={() => alert('Link to help')} />
<DrawerItem
label="Close drawer"
onPress={() => props.navigation.closeDrawer()}
/>
</DrawerContentScrollView>
);
}
const Drawer = createDrawerNavigator();
function MyDrawer() {
return (
<Drawer.Navigator drawerContent={props => CustomDrawerContent(props)}>
<Drawer.Screen name="Feed" component={mn} />
<Drawer.Screen name="Article" component={Article} />
</Drawer.Navigator>
);
}
export default class drawerapp extends React.Component {
render(){
const {navigate} = this.props.navigation;
return (
<NavigationContainer>
<MyDrawer />
</NavigationContainer>
);
}}
my work perfectly fine until i click on the left header button and the error appear
u are getting the navigation prop in wrong place, headerLeft does not give navigation prop, so u have to get it from navigationOptions...
change the navigator code as below..
const Navigator = createStackNavigator({
Home:{screen: Home},
Profil:{screen: Inscription},
signup:{screen: signup, navigationOptions: { header: null }},
mp:{screen: mp},
ch:{screen: ch},
mn:{screen: mn},
drawer:{screen: drawer,
navigationOptions: ({navigation}) => ({
title:"votre travail",
headerStyle:{backgroundColor:'#8B0000'},
headerTitleStyle: {
fontWeight: 'bold',
color:'white',
},
headerLeft: () => (
<TouchableOpacity onPress={() => navigation.openDrawer()} >
<Icon name={'menu'} size={28} color={'white'} style={{marginRight:10}}/>
</TouchableOpacity>
),
}),
},
});

How to hide Tab conditionally in react-navigation?

I want to hide one of my tabs conditionally if user login,
So I have 5 Tabs If user login\register I get a boolean from a redux store,
if this user login i want to how a "Library tab" if not login, i don't want to show this tab "Library" with others and just keep 4 tabs in the App
Code
import {createAppContainer} from 'react-navigation';
import {createBottomTabNavigator} from 'react-navigation-tabs';
let {isLogin} = store.getState().user;
const TabHome = createBottomTabNavigator(
{
Home: {
screen: Home,
navigationOptions: {
tabBarLabel: 'Home',
},
},
Browse: {
screen: Browse,
navigationOptions: {
tabBarLabel: 'Browse',
},
},
Search: {
screen: Search,
navigationOptions: {
tabBarLabel: 'Search',
headerShown: false,
},
},
Radio: {
screen: Radio,
navigationOptions: {
tabBarLabel: 'Radio',
},
},
Library: isLogin ? (
{
screen: YourLibrary,
navigationOptions: {
tabBarLabel: 'Library',
},
}
) : (
<View /> // Or :null => Not work and got the under error msg
),
// Library: {
// screen: YourLibrary,
// },
},
)
export default createAppContainer(TabHome);
Error: The component for route 'Library' must be a React component.
For example:
import MyScreen from './MyScreen'; ... Library: MyScreen, }
You can also use a navigator:
import MyNavigator from './MyNavigator'; ... Library: MyNavigator, }
In React Navigation v5:
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
function HomeScreen(props) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
);
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
);
}
function AboutScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>About!</Text>
</View>
);
}
const Tab = createBottomTabNavigator();
function MyTabs() {
const [showTab, setShowTab] = React.useState(true);
// Show the about tab after 5 seconds.
// Change this to use Redux or however
// you would like to change which tabs are displayed
setTimeout(() => {
setShowTab(false);
console.log('Hide tab');
}, 5000);
return (
<Tab.Navigator>
<Tab.Screen
name="Home"
component={HomeScreen}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
),
}}
/>
{showTab ? (
<Tab.Screen
name="About"
component={AboutScreen}
options={{
tabBarLabel: 'About',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="book" color={color} size={size} />
),
}}
/>
) : null}
<Tab.Screen
name="Settings"
component={SettingsScreen}
options={{
tabBarLabel: 'Settings',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="settings" color={color} size={size} />
),
}}
/>
</Tab.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<MyTabs />
</NavigationContainer>
);
}
Example in Expo https://snack.expo.io/#jackvial/createbottomtabnavigator-%7C-react-navigation-v5
You'd know that you can override the Tabbar Component and add your own logic for it?
Maybe this gives you an Idea about that: https://stackoverflow.com/a/58520533/1256697
Maybe this way, you can set conditional styles to show or hide single items of your TabBar.
remove Library tab definition from TabHome and add it just before exporting the component:
if(isLogin) {
TabHome.Library = {
screen: YourLibrary,
navigationOptions: {
tabBarLabel: 'Library',
}
}
}
export default createAppContainer(TabHome)

How to force stackNavigator to target MainScreen?

I have implemented a StackNavigator and a DrawerNavigator, in my DrawerNavigator in the first option I am calling StackNavigator. The problem is that when I'm browsing Stack screens I wanted to go back to the main screen through Drawer but this doesn't happen because Stack stores the last screen the user was on.
I have tried using some Navigation Prop but I am not sure where to insert this code or even which of the commands to use on the stack.
MenuDrawer.js
import React from 'react';
import {
View,
ScrollView,
Text,
StyleSheet,
TouchableOpacity,
Image,
Dimensions
} from 'react-native';
export default class MenuDrawer extends React.Component{
navLink(nav, text) {
return(
<TouchableOpacity style={{height: 50}} onPress={() => this.props.navigation.navigate(nav)}>
<Text style={styles.link}>{text}</Text>
</TouchableOpacity>
)
}
render() {
return(
<ScrollView styles={styles.continer}>
<View style={styles.topImage}>
<Image style={styles.image} source={require('../images/informationappscreen/act.png')} />
</View>
<View style={styles.bottomLinks}>
{this.navLink('Principal', 'Principal')}
{this.navLink('Sobre o Aplicativo', 'Sobre o Aplicativo')}
{this.navLink('Sobre os Responsáveis', 'Sobre os Responsáveis')}
{this.navLink('Sobre o Projeto', 'Sobre o Projeto')}
{this.navLink('Política e Termos', 'Política e Termos')}
</View>
<View style={styles.footer}>
<Text style={styles.description}>ACT</Text>
<Text style={styles.version}>v1.3.0</Text>
</View>
</ScrollView>
);
}
}
App.js
import React from 'react';
import { View, Dimensions } from 'react-native';
import { Button, Icon } from 'native-base';
import { createAppContainer, createStackNavigator, createDrawerNavigator } from 'react-navigation';
...
const HomeNavigator = createStackNavigator ({
'Main1': {
screen: Main1,
navigationOptions: {
title: 'Menu Principal',
headerRight: (<View></View>)
}
},
'Main2': {
screen: Main2,
navigationOptions: {
title: 'Menu Principal',
headerRight: (<View></View>)
},
},
'SecondMain': {
screen: SecondMain,
navigationOptions: {
title: 'Menu Querer'
}
},
'Action1': {
screen: Action1,
navigationOptions: {
title: 'Ações'
}
},
...
}, {
defaultNavigationOptions: ({ navigation }) => {
return {
headerTitleStyle: {
fontWeight: 'bold'
},
headerLeft: (
<Button transparent onPress={() => navigation.toggleDrawer()}>
<Icon name='menu' style={{color: '#FFF'}} />
</Button>
),
headerRight: (
<HomeIcon navigation={navigation} />
),
headerStyle: {
backgroundColor: '#b80003'
},
headerTintColor: '#FFF'
}
}
});
const DrawerConfig = {
drawerWidth: Dimensions.get('window').width * 0.75,
contentComponent: ({ navigation }) => {
return(<MenuDrawer navigation={navigation} />)
}
}
const DrawerNavigator = createDrawerNavigator (
{
'Principal': {
screen: HomeNavigator
},
'Sobre o Aplicativo': {
screen: InformationApp
},
'Sobre os Responsáveis': {
screen: Team
},
'Sobre o Projeto': {
screen: Project
},
'Política e Termos': {
screen: Policy
}
},
DrawerConfig
);
const AppDrawerContainer = createAppContainer(DrawerNavigator);
export default AppDrawerContainer;
Can you try reset , change method navLink
import { StackActions, NavigationActions } from 'react-navigation';
navLink(nav, text) {
return (
<TouchableOpacity
style={{ height: 50 }}
onPress={() => {
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: nav })]
});
this.props.navigation.dispatch(resetAction);
}}
>
<Text style={styles.link}>{text}</Text>
</TouchableOpacity>
);
}
Try using this.props.navigation.push('your_pagename') this will push new item to the stack. It means when using push componentDidMount() method call again

How to render the same component on all screens?

I have a StackNavigator, where I've specified the same headerRight Icon for every screen:
export default StackNavigator(
{
Authorization: {
screen: AuthorizationScreen
},
SignIn: {
screen: SignInScreen
},
SignUp: {
screen: SignUpScreen
},
Main: {
screen: MainScreen
},
Language: {
screen: LanguageScreen
},
//...etc
},
{
navigationOptions: {
headerRight: (
<Icon color={'#77767c'}
name='ios-contact-outline'
size={30}
style={{ paddingRight: 30}}
type='ionicon'
/>
),
}
}
)
All the screens are imported from separate files. When this Icon is pressed, I want the same component to render regardless of what screen I'm on. The problem is, I can't think of a way to do this outside of writing in some kind of state handling and onPress function for every single screen I have, which would be really tedious to write and maintain. Is there any way to get around this and only write the component rendering once?
You can create one component for Header and pass it into all the screen's navigationOptions. Then you just need to handle the method on each screen and you can do your stuff at here.
Custom Header Class:
class Header extends Component {
render() {
const props = this.props;
return (<View>
<View
style={KEEP_YOUR_STYLE}
/>
<View style={styles.containerStyle} >
<Text
style={your_style}
numberOfLines={1}
>TITLE</Text>
<TouchableOpacity
style={styles.touchableOpacityStyle}
onPress={props.onPress}
>
<Image
source={YOUR_ICON}
style={{
position:'absolute',
right: 10,
width: 20,
height: 20,
resizeMode: 'cover',
}
} />}
</TouchableOpacity>
</View>
</View>
);
}
}
export { Header };
In your StackNavigator:
const defaultNavigation = ({ navigation }) => ({
header: (<Header
title='Hellow'
/>),
});
Language: {
screen: LanguageScreen,
navigationOptions: defaultNavigation,
},
In your particular Screen:
static navigationOptions = ({ navigation }) => ({
header: (
<Header
title='Your Title'
onPress={() => {
// DO YOUR STUFF
}}
/>),
});

React Native TabNavigator, Cannot read property 'navigate' of undefined

I've just set up a React Navigation TabNavigator which works fine but I'm having issues with transitions between my views.
I get the following error message from trying to redirect the user to another page after a click on a button.
Cannot read property 'navigate' of undefined
I'm super confused on how to make this work.
Here is the navigator:
import React from 'react';
import { TabNavigator, StackNavigator } from 'react-navigation';
import ElemList from './src/components/ElemList';
import ElemShow from './src/components/ElemShow';
const RootTabs = TabNavigator({
Home: {
screen: ElemList,
navigationOptions: {
tabBarLabel: 'Home',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-home' : 'ios-home-outline'}
size={26}
style={{ color: tintColor }}
/>
),
},
main: {
screen: StackNavigator({
show: { screen: ElemShow },
})
}
}
});
Here is my code:
onRowPress(data) {
this.props.navigation.navigate('ElemShow', {id: data})
};
render() {
const { key, elem } = this.props;
return (
<TouchableWithoutFeedback onPress={() => this.onRowPress(elem)}>
<View style={styles.viewStyle} key={key}>
<Text>Here is the info</Text>
</View>
</TouchableWithoutFeedback>
)
}
The problem is with this line
this.props.navigation
Should be
this.props.navigator
Additionally I don't know that navigate is part of the screens API; typically you will use push or resetTo.

Categories