I customize TabBarCompenet and trying to pass cart value so that could keep updated cart on value change. But app throws error
Undefined is not an object '_this.state.cartAmount'
App.js
var {height, width} = Dimensions.get('window');
const DashboardTabNavigator = createBottomTabNavigator({
Tab1: {screen: FoodCategoryStack},
Tab2: {screen: EventsStack}
},
{
tabBarComponent:({ props }) => (
<AddTabButton {...props} cartAmount={this.state.cartAmount} />
)});
const DashboardStackNavigator = createStackNavigator({
DashboardTabNavigator: DashboardTabNavigator
},
{
defaultNavigationOptions: ({ navigation }) => {
return {
header: null,
headerLeft: <MaterialIcons
onPress={() => navigation.openDrawer()}
style={{ paddingLeft: 10 }}
name="menu"
size={30}
/>
};
}
}
);
const CustomDrawerComponent = (props) => (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ height: 150, backgroundColor: 'white', alignItems: 'center', justifyContent: 'center', marginTop: 20 }}>
</View>
<ScrollView>
<DrawerItems {...props} />
</ScrollView>
</SafeAreaView>
)
const AppDrawerNavigator = createDrawerNavigator({
Home: {
screen: DashboardStackNavigator,
},
Events: {
screen: EventScreen
}
},
{
contentComponent: CustomDrawerComponent,
drawerWidth: width * 0.85
});
const AppSwitchNavigator = createSwitchNavigator({
Welcome: { screen: splashScreen },
Dashboard: { screen: AppDrawerNavigator }
});
const AppContainer = createAppContainer(AppSwitchNavigator);
export default class App extends React.Component {
constructor(props){
super(props)
this.state = {
cartAmount: '18.50'
}
}
componentWillMount() {
console.log('componentWillMount Tab View')
}
componentDidMount() {
console.log('componentDidMount Tab View')
console.log(this.state.cartAmount)
}
HandleTabPressOne () {
console.log('Cart function called')
this.setState({ cartAmount: '12.20' });
alert(this.state.cartAmount)
}
render() {
return ( <AppContainer{...this.props} />);
}
}
AddTabButton.js
import React, {Component} from 'react';
import {StyleSheet, Animated, Text, TouchableOpacity, View, Dimensions} from "react-native";
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
var {height, width} = Dimensions.get('window');
const AddTabButton = (props) => {
return (
<View style={{flex: 0.1, backgroundColor: '#FF0000', borderColor: '#FF0000', borderWidth: 1}}>
<View style={{flexDirection:'row', justifyContent: 'space-around', alignItems: 'center', paddingTop: 5}}>
<TouchableOpacity onPress={() => navigation.navigate('Tab1')} style={{alignItems: 'center', marginLeft: 5}}>
<MaterialIcons name="local-pizza" size={24} color="#FFFFFF" />
<Text style={styles.textFAB}>Menu</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.HandleTabPressOne}style={{alignItems: 'center'}}>
<MaterialIcons name="event-available" size={24} color="#FFFFFF" />
<Text style={styles.textFAB}>Event</Text>
</TouchableOpacity>
<View style={styles.cartFAB}>
<MaterialIcons name="shopping-basket" size={24} color="#FFFFFF" style={{marginTop: 10}} />
<Text style={styles.totalCart}>$ {(this.props.cartAmount != null) ? this.props.cartAmount : '12.55'}</Text>
</View>
</View>
</View>
);
};
export default AddTabButton;
As per suggestion of Andrew I implemented redux to overcome the scenario.
Related
I'm having an issue with the "onLogin" function within the "LoginComponent". After pressing the TouchableOpacity that handles that function, I want the user to then be directed to the "HomeComponent", but instead I get this console.error: "the action navigate with payload...was not handled..." Anybody know why this is? Any help would be greatly appreciated. Thanks!
import React, { Component } from 'react';
import 'react-native-gesture-handler';
import { createStackNavigator } from '#react-navigation/stack';
import WelcomeScreen from './WelcomeComponent';
import LoginScreen from './LoginComponent';
import RegisterScreen from './RegisterComponent';
import HomeScreen from './HomeComponent';
import { NavigationContainer } from '#react-navigation/native';
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
import { AsyncStorage } from 'react-native';
const AuthStack = createStackNavigator();
const AuthStackScreen = () => {
return <AuthStack.Navigator initialRouteName="Welcome">
<AuthStack.Screen name="Welcome" component={WelcomeScreen} />
<AuthStack.Screen name="Login" component={LoginScreen} />
<AuthStack.Screen name="Register" component={RegisterScreen} />
</AuthStack.Navigator>
};
const HomeTab = createMaterialBottomTabNavigator();
const HomeTabScreen = () => {
return <HomeTab.Navigator initialRouteName="Home">
<HomeTab.Screen name="Home" component={HomeScreen} />
</HomeTab.Navigator>
}
class Navigation extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: false,
};
this.loginStatusCheck();
}
loginStatusCheck = async () => {
const userToken = await AsyncStorage.getItem("userprofile");
if(userToken) {
this.setState({ isLoggedIn: true })
} else {
this.setState({ isLoggedIn: false })
}
}
render() {
return(
<NavigationContainer>
{this.state.isLoggedIn ? <AuthStackScreen /> : <HomeTabScreen />}
</NavigationContainer>
);
};
};
export default Navigation;
import React, { Component } from 'react';
import { StyleSheet, SafeAreaView, ScrollView, View, TouchableOpacity, Text, Linking, AsyncStorage } from 'react-native';
import { Input, CheckBox } from 'react-native-elements';
import { FontAwesome } from '#expo/vector-icons';
class LoginScreen extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password:"",
token: "",
remember: false
};
this.getData();
};
handleUsernameChange = username => {
this.setState({ username })
};
handlePasswordChange = password => {
this.setState({ password })
};
onLogin = async () => {
try {
await AsyncStorage.setItem("userprofile", JSON.stringify({ username: this.state.username, password: this.state.password }));
this.props.navigation.navigate("Home", {
screen: "HomeScreen",
});
} catch (err) {
console.log(err);
}
};
getData = async () => {
try {
const userprofile = await AsyncStorage.getItem("userprofile");
const userProfile = JSON.parse(userprofile);
if (userProfile !== null) {
this.setState({ ...userProfile })
}
if (username !== null) {
this.setState({ username })
}
if (password !== null) {
this.setState({ password })
}
} catch (err) {
console.log(err);
}
}
render() {
const { username, password } = this.state;
return (
<SafeAreaView style={styles.container}>
<ScrollView>
<Text style={styles.titleText}>Login</Text>
<Text style={styles.fillerText}>Hi there! Nice to see you again.</Text>
<Input
inputStyle={{color: 'white'}}
placeholder="Enter username"
onChangeText={this.handleUsernameChange}
value={username}
keyboardType="email-address"
autoCapitalize="none"
leftIcon={{ type: 'font-awesome', name: 'user-circle-o', color: 'white', marginRight: 10 }}
/>
<Input
inputStyle={{color: 'white'}}
placeholder="Password"
secureTextEntry
onChangeText={this.handlePasswordChange}
value={password}
leftIcon={{ type: 'font-awesome', name: 'lock', color: 'white', marginRight: 10 }}
/>
<CheckBox
title="Remember Me"
checked={this.state.remember}
onPress={() => this.setState({remember: !this.state.remember})}
containerStyle={styles.rememberCheckbox}
textStyle={{color: 'white'}}
checkedColor="crimson"
/>
<TouchableOpacity
style={styles.loginButton}
title="Login" type="submit"
onPress={this.onLogin}
>
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
<Text style={{textAlign: 'center', color: 'grey', marginTop: 20}}>
OR use an account from one of the following:
</Text>
<View style={styles.buttonsContainer}>
<TouchableOpacity style={styles.twitterButton}>
<FontAwesome name="twitter" color="white" style={{marginRight: 5}}/>
<Text style={{color: 'white'}}>Twitter</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.facebookButton}>
<FontAwesome name="facebook-square" color="white" style={{marginRight: 5}}/>
<Text style={{color: 'white'}}>Facebook</Text>
</TouchableOpacity>
</View>
<View style={{alignItems: 'center'}}>
<TouchableOpacity style={styles.googleButton}>
<FontAwesome name="google" color="black" style={{marginRight: 5}}/>
<Text style={{color: 'grey'}}>Google</Text>
</TouchableOpacity>
</View>
<View style={styles.linkContainer}>
<TouchableOpacity style={{marginTop: 75}} onPress={() => Linking.openURL('#')}>
<Text style={{color: 'white'}}>
Forgot Your Password?
</Text>
</TouchableOpacity>
<TouchableOpacity style={{marginTop: 75, marginLeft: 210}} onPress={() => Linking.openURL('#')}>
<Text style={{color: 'white'}}>
Register
</Text>
</TouchableOpacity>
</View>
</ScrollView>
</SafeAreaView>
);
};
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: 'black'
},
buttonsContainer: {
flex: 2,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row'
},
linkContainer: {
flex: 3,
justifyContent: 'center',
flexDirection: 'row'
},
titleText: {
fontSize: 26,
color: 'white',
marginBottom: 30,
marginTop: 20
},
fillerText: {
color: 'grey',
marginBottom: 20
},
loginButton: {
backgroundColor: 'crimson',
paddingVertical: 17,
paddingHorizontal: 25,
borderRadius: 20,
textAlign: 'center'
},
buttonText: {
color: 'white',
fontSize: 18,
textAlign: 'center'
},
twitterButton: {
backgroundColor: '#00acee',
marginTop: 20,
padding: 10,
justifyContent: 'center',
alignItems: 'center',
width: '40%',
marginLeft: 20,
flexDirection: 'row',
borderRadius: 20
},
facebookButton: {
backgroundColor: '#4267B2',
marginTop: 20,
padding: 10,
justifyContent: 'center',
alignItems: 'center',
width: '40%',
marginLeft: 20,
flexDirection: 'row',
borderRadius: 20
},
googleButton: {
backgroundColor: '#FFFFFF',
marginTop: 20,
padding: 10,
justifyContent: 'center',
alignItems: 'center',
width: '40%',
marginLeft: 20,
flexDirection: 'row',
borderRadius: 20
},
rememberCheckbox: {
margin: 10,
marginBottom: 20,
backgroundColor: null
}
});
export default LoginScreen;
I don't think its necessary to use navigate in your LoginScreen component, since you've already written code that conditionally renders two navigators based on the value of isLoggedIn.
What you're missing in your current implementation is a way to update isLoggedIn from within your LoginScreen component. Then if isLoggedIn is updated and set to true, the Navigation component will be re-rendered and the HomeScreen component is shown without having to navigate.
I've chosen to use react context here, but you could also use this approach with something like redux also if you prefer that. The reason to use something like react context is to be able to easily pass isLoggedIn and its setter between components.
I'll give a more general example, because its easier to illustrate the approach that way:
// Imports and other stuff...
const LoginContext = React.createContext([null, () => {}]);
const LoginContextProvider = props => {
const [isLoggedIn, setIsLoggedIn] = React.useState(false);
return (
<LoginContext.Provider value={[isLoggedIn, setIsLoggedIn]}>
{props.children}
</LoginContext.Provider>
);
};
const HomeScreen = () => {
return (
<View>
<Text>HomeScreen</Text>
</View>
);
};
const LoginScreen = () => {
const [isLoggedIn, setIsLoggedIn] = React.useContext(LoginContext);
return (
<View>
<Text>LoginScreen</Text>
<Button
title="login"
onPress={() => {
setIsLoggedIn(true);
}}
/>
</View>
);
};
const HomeTabScreen = () => {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
</Tab.Navigator>
);
};
const AuthStackScreen = ({ navigation }) => {
return (
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} />
</Stack.Navigator>
);
};
const Navigation = () => {
const [isLoggedIn, setIsLoggedIn] = React.useContext(LoginContext);
return (
<NavigationContainer>
{isLoggedIn ? <HomeTabScreen /> : <AuthStackScreen />}
</NavigationContainer>
);
};
export default function App() {
return (
<LoginContextProvider>
<Navigation />
</LoginContextProvider>
);
}
So the approach shown above is to create a provider that holds your isLoggedIn state and setter (setIsLoggedIn). Then when we wrap Navigation with this provider so we can access isLogged and setIsLoggedIn from any component inside the provider, allowing us to update the isLogged state inside the LoginScreen component. When this state updates, the provider and everything inside it (i.e. Navigation), will re-render and show the HomeScreen component.
Normally the convention is to put most the react context related stuff in its own file and import parts in components where you need them, but for demonstration purposes I haven't done this.
I've managed to set up Google login using 'expo-google-app-auth'.
This is my Login.js, which handles the login page and the google login details and logic:
import React, { Component } from 'react'
import {Text,
View,
StyleSheet,
Image,
Alert} from 'react-native'
import { TouchableOpacity } from 'react-native-gesture-handler';
import { Provider as PaperProvider,
Button,
Caption} from 'react-native-paper'
import { createStackNavigator } from '#react-navigation/stack'
import { NavigationContainer } from '#react-navigation/native';
import MyDrawer from '../navigation/Drawer'
import QR from './QR'
const Stack = createStackNavigator();
import * as Google from 'expo-google-app-auth';
const IOS_CLIENT_ID =
"your-ios-client-id";
const ANDROID_CLIENT_ID =
"my-android-id";
class Login extends Component {
signInWithGoogle = async () => {
try {
const result = await Google.logInAsync({
iosClientId: IOS_CLIENT_ID,
androidClientId: ANDROID_CLIENT_ID,
scopes: ["profile", "email"]
});
if (result.type === "success") {
console.log("LoginScreen.js.js 21 | ", result.user.givenName, result.user.familyName, result.user.email, result.user.photoUrl);
this.props.navigation.navigate("MyDrawer", {
username: result.user.givenName,
lastname: result.user.familyName,
email: result.user.email,
photoUrl: result.user.photoUrl
}); //after Google login redirect to MyDrawer
return result.accessToken;
} else {
return { cancelled: true };
}
} catch (e) {
console.log('LoginScreen.js.js 30 | Error with login', e);
return { error: true };
}
};
render(){
return (
<PaperProvider>
<View style={styles.container}>
<View style={styles.imageCon}>
<Image
source={require('../img/logo-krug.png')}></Image>
</View>
<View style={styles.textCon}>
<Text style={styles.text}> Dobrodošli u eSTUDENT mobilnu aplikaciju!</Text>
</View>
<View style={styles.buttonCon}>
<Button
icon='camera'
mode='outlined'
onPress={this.signInWithGoogle}
>
google
</Button>
</View>
</View>
</PaperProvider>
)
}
}
export default function LoginStack() {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName='Login'
screenOptions={{
headerShown: false
}}>
<Stack.Screen name='MyDrawer' component={MyDrawer} />
<Stack.Screen name='Login' component={Login} />
</Stack.Navigator>
</NavigationContainer>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ecf0f1'
},
imageCon: {
height: '35%',
width: '100%',
justifyContent: "center",
alignItems: "center"
},
textCon:{
height:'20%',
alignItems: 'center',
justifyContent: 'center'
},
text: {
textAlign: "center",
fontSize: 20,
fontWeight: 'bold'
},
buttonCon:{
height: '30%',
justifyContent:'center',
alignItems: 'center'
},
});
And I want to pass the username, family name, email and profile picture to these 2 files.
Drawer.js, which handles the side Drawer and navigation:
import React from 'react'
import { createDrawerNavigator } from '#react-navigation/drawer';
import { NavigationContainer } from '#react-navigation/native';
import { Ionicons, MaterialIcons, Feather } from '#expo/vector-icons';
import { ScrollView,
TouchableOpacity,
Text,
View,
Image,
StatusBar,
StyleSheet,
} from 'react-native'
import QR from '../screens/QR';
import Odabir from '../screens/Odabir'
import { SafeAreaView } from 'react-navigation';
import { Divider } from 'react-native-paper'
const Drawer = createDrawerNavigator();
function CustomDrawerContent(props) {
return(
<SafeAreaView style={{flex:1}}>
<View style={{height: 150, alignItems: 'center', justifyContent: 'center', marginTop: Platform.OS === 'ios' ? 0 : StatusBar.currentHeight}}>
<Image source={require('../img/account.png')}
style={{height: 120, width: 120, borderRadius: 60}}
/>
</View>
<View style={{height: 50, alignItems:'center'}}>
<Text style={styles.naslov}> This is where I want to pass the username and last name </Text>
</View>
<Divider />
<ScrollView style={{marginLeft: 5,}}>
<TouchableOpacity
style={{marginTop: 20, marginLeft: 20}}
onPress={() => props.navigation.navigate('QR')}
>
<View style={{padding:10}}>
<Ionicons name='ios-qr-scanner' size={20} styles={{}}>
<Text style={styles.naslov}> QR</Text>
</Ionicons>
</View>
</TouchableOpacity>
<TouchableOpacity
style={{marginTop: 20, marginLeft: 20}}
onPress={() => props.navigation.navigate('Odabir')}
>
<View style={{padding:10}}>
<Ionicons name='ios-qr-scanner' size={20} styles={{}}>
<Text style={styles.naslov}> Odabir</Text>
</Ionicons>
</View>
</TouchableOpacity>
<TouchableOpacity
style={{marginTop: 20, marginLeft: 20}}
onPress={() => props.navigation.navigate('Odabir')}
>
<View style={{padding:10}}>
<Ionicons name='ios-qr-scanner' size={20} styles={{}}>
<Text style={styles.naslov}> Odabir</Text>
</Ionicons>
</View>
</TouchableOpacity>
</ScrollView>
</SafeAreaView>
)
}
export default function MyDrawer() {
return (
<NavigationContainer independent={true}>
<Drawer.Navigator initialRouteName='QR' drawerContent={props => CustomDrawerContent(props)}>
<Drawer.Screen
name="QR"
component={QR}
/>
<Drawer.Screen
name="Odabir"
component={Odabir}
/>
</Drawer.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
naslov: {
fontSize: 20,
},
})
and finally QR.js, which holds some basic information and I'd like to personalize it a bit since it's the 'Home' page users land on
import React, { Component } from 'react'
import {Text,
SafeAreaView,
View,
StyleSheet,
Image
} from 'react-native'
import Header from '../navigation/Header'
export default function QR({navigation}) {
return (
<SafeAreaView style={styles.container}>
<Header title='Moj QR' isHome={true} navigation={navigation}/>
<View style={styles.qrCon}>
<Image
style={styles.qr}
source={require('../img/QR_code_for_mobile_English_Wikipedia.svg.png')}
/>
</View>
<View style={styles.textCon}>
<Text style={styles.text}>This is where I want to pass the username and last name</Text>
<Text style={styles.text}>Ovo je tvoj QR kod</Text>
</View>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ecf0f1',
alignItems: 'center',
},
qrCon:{
width: '60%',
height: '60%',
alignItems: 'center',
justifyContent: 'center',
},
qr: {
width: '120%',
height: '120%',
resizeMode: 'contain'
},
textCon: {
height: '7%'
},
text:{
fontSize: 35,
fontWeight: '600'
},
buttonCon:{
height: '15%',
justifyContent:'center',
alignItems: 'center'
}
})
The example I'm following used {this.props.navigation.getParam("username")} but that isn't working for me. How would I exactly pass the data?
I had this issue recently. React navigation 5 doesn't support props.navigation.getParam instead you can use this.props.route.params to access the data you passed in your navigation prop. So to access the username you can use this.props.route.params.username;
The way to solve this, at least passing data to the Drawer.js component is to rewrite the code like this:
if (result.type === "success") {
console.log("LoginScreen.js.js 21 | ", result.user.givenName, result.user.familyName, result.user.email, result.user.photoUrl);
this.props.navigation.navigate("MyDrawer",
username = result.user.givenName,
lastname = result.user.familyName,
email = result.user.email,
photoUrl = result.user.photoUrl);
return result.accessToken;
;
Then just putting that as a variable in Drawer.js
<View style={{height: 30, alignItems:'center'}}>
<Text style={styles.naslov}>{username} {lastname}</Text>
</View>
I try to add brackets or semicolon, but get error:
Syntax error: Unexpected token
How I can implement this functionality and make this work correct? My full code:
Also, why is it not working?
import React, { Component } from 'react';
import { Text, ActivityIndicator, View, Button, TextInput, StyleSheet, TouchableOpacity, Dimensions, AppRegistry, Platform, StatusBar, AsyncStorage } from 'react-native';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
const userInfo = {username: 'admin', password: 'pass12345'}
class HomeScreen extends Component {
static navigationOptions = { header: null }
constructor(props) {
super(props);
this.state = { username: '', password: '' }
}
render() {
return (
<View style={styles.container}>
<Text>News</Text>
<TextInput
style={styles.input}
placeholder={'Username'}
onChangeText={(username)=>this.setState({username})}
value={this.state.username}
autoCapitalize="none"
/>
<TextInput
style={styles.input}
placeholder={'Password'}
secureTextEntry={true}
onChangeText={(password)=>this.setState({password})}
value={this.state.password}
/>
<View>
<TouchableOpacity
style={styles.btnLogin}
onPress={this._login}
//onPress={() => this.props.navigation.navigate('Details')}
>
<Text style= {styles.text}>Login</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => alert("Signup Works")} >
<Text style={styles.btnTxt}>Signup</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
class DetailsScreen extends Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
);
}
}
const RootStack = createStackNavigator({
//Home: HomeScreen,
Details: DetailsScreen
}, {//initialRouteName: 'Home'} );
defaultNavigationOptions:{
headerStyle:{
backgroundColor: '#1e90ff'
},
headerTitleStyle: {
textAlign:'center',
flex: 1
}
}
},
};
const AuthStack = createStackNavigator({Home: HomeScreen});
class AuthLoadingScreen extends Component {
constructor (props){
super(props);
this._loadData();
}
render(){
return(
<View>
<ActivityIndicator/>
<StatusBar barStyle="default"/>
</View>
);
}
_loadData = async() => {
const isLogged = await AsyncStorage.getItem('isLoggedIn');
this.prop.navigation.navigate(isLoggedIn !== '1'? 'Auth':'App');
}
}
export default createAppContainer(
createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: RootStack,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
)
);
_login = async() => {
if (userInfo.username === this.state.username && userInfo.password === this.state.password) {
//alert('Logged In');
await AsyncStorage.setItem('isLoggedIn', '1');
this.props.navigation.navigate('Details')
} else {
alert('Username or Password is incorrect.');
}
}
const styles = StyleSheet.create({
container:{ flex:1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#00bfff', },
btnLogin: { flex: 0.5, height: 45, borderRadius: 25, fontSize: 16, justifyContent: 'center', marginTop: 20 },
btnTxt:{ },
input:{ justifyContent: 'center', width:"90%", padding: 15, marginBottom: 10 }
});
Expo Error
At a glance this seems like a problem:
}, {//initialRouteName: 'Home'} );
You've commented out the closing } and closing ).
I am using react navigation, and I want to update some text whenever user change the data.
const AppDrawNavigator = createDrawerNavigator({
Home: {screen: HomeStackNavigator},
Rewards: {screen: RewardsStackNavigator},
Flavours: {screen: FlavoursTabNavigatorClass}
}, {
contentComponent: CustomeDrawer
})
const CustomeDrawer = (props) => {
return(
<SafeAreaView style={{flex:1}}
forceInset={{ top: 'always', horizontal: 'never' }}>
<View style={{height: 150, backgroundColor:'white'}}>
<Text style={{color: 'black', fontSize: 18, fontWeight: 'bold'}}>customDrawer</Text>
<Text> {/* Here i want to display updated text */} </Text>
</View>
<ScrollView>
<DrawerNavigatorItems {...props} />
</ScrollView>
</SafeAreaView>
)
}
I got the answer. I don't know whether this is correct approach or not.? But this seems to working for me.
const CustomeDrawer = (props) => {
return(
<SafeAreaView style={{flex:1}}
forceInset={{ top: 'always', horizontal: 'never' }}>
<View style={{height: 150, backgroundColor:'white'}}>
<Text style={{color: 'black', fontSize: 18, fontWeight: 'bold'}}>My customeDrawer Text</Text>
</View>
<ScrollView>
**<CustomDrawer />**
<DrawerNavigatorItems {...props}/>
</ScrollView>
</SafeAreaView>
)
}
{/* Here we will define the main screen of drawer navigator */}
const AppDrawNavigator = createDrawerNavigator({
Home: {screen: HomeStackNavigator},
Rewards: {screen: RewardsStackNavigator},
Flavours: {screen: FlavoursTabNavigatorClass}
}, {
contentComponent: CustomeDrawer
})
In my custom Drawer component:
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity, SafeAreaView, AsyncStorage} from 'react-native';
export default class CustomDrawer extends React.Component {
constructor(props) {
super(props);
this.state = {
name: ''
}
}
componentDidMount = () => {
AsyncStorage.getItem('name').then((name) => this.setState({name}))
}
render() {
return (
<SafeAreaView style={{flex:1, width: '100%', alignItems:'center', justifyContent:'center'}}>
<Text style={{width:'100%'}}>
{this.state.name}
</Text>
</SafeAreaView>
);
}
}
I have to render headerRight conditionally in navigation options.
Right now
static navigationOptions = ({ navigation }) => ({
title: i18N.t('atmbranchpickHeader'),
headerRight: (
<TouchableHighlight
underlayColor="#E22F39"
onPress={() => {
navigation.navigate("home");
}}
>
<Image
style={{ marginRight: 20 }}
source={require('../../resources/toolbar/home_white.png')}
/>
</TouchableHighlight>
),
headerTintColor: "white",
headerStyle: {
backgroundColor: "#E22F39"
// top: 30
}
});
My Component
import React, { Component } from "react";
import {
View,
TextInput,
Text,
TouchableOpacity,
TouchableHighlight,
StyleSheet,
AsyncStorage,
BackHandler,
Image,
FlatList,
Dimensions,
TouchableWithoutFeedback
} from "react-native";
import i18n from "../../i18n/i18n.js";
import { colors } from "../../constants/colors.js";
import Storage from "../../utils/AsyncStorage.js";
class AtmBranchTypeSelect extends Component {
// Render callBack
constructor(props) {
super(props);
this.state = {
data: [
],
stBool: false,
}
}
async componentWillMount() {
BackHandler.addEventListener('hardwareBackPress', () => this.props.navigation.goBack());
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', () => this.props.navigation.goBack());
}
static navigationOptions = ({ navigation }) => ({
title: i18n.t('atmbranchpickHeader'),
headerRight: (
<TouchableHighlight onPress={() => {
navigation.navigate('home');
}}>
<Image style={{ marginRight: 20 }} source={require('../../resources/toolbar/home_white.png')} />
</TouchableHighlight>),
headerTintColor: 'white',
headerStyle: {
backgroundColor: colors.themeColor,
// top: 30
}
});
_renderList = ({ item }) => {
return (
<TouchableWithoutFeedback onPress={(event) => this._selectedItem(item.key)}>
<View style={styles.listRowContainer}>
<View style={styles.listinside1Container}>
<Image style={styles.listImage} source={item.icon} />
<View style={styles.listContainer} onPress={(event) => this._selectedItem(item.text)} >
<Text style={styles.listHeader} >{item.header}</Text>
<Text style={styles.listValue} >{item.value}</Text>
</View>
</View>
<Image style={styles.listimgArrow} source={require('../../resources/toolbar/chevron_right_grey.png')} />
</View>
</TouchableWithoutFeedback>
);
}
// Render callBack
render() {
return (
<View style={styles.mainWrapper} >
<FlatList data={this.state.data} renderItem={this._renderList} />
</View>
);
}
}
const styles = StyleSheet.create({
mainWrapper: {
flex: 1,
height: Dimensions.get('window').height,
width: Dimensions.get('window').width,
flexDirection: 'column',
justifyContent: 'flex-start'
},
listRowContainer: {
flexDirection: 'row',
marginTop: 10,
height: 80,
backgroundColor: '#FFFFFF',
justifyContent: 'space-between',
borderBottomWidth: 1,
borderColor: 'lightgray'
},
listinside1Container: {
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center'
},
listContainer: {
alignItems: 'flex-start',
justifyContent: 'center',
flexDirection: 'column',
backgroundColor: '#FFFFFF',
// borderBottomWidth: 1,
// borderColor: 'lightgray'
},
listHeader: {
color: 'black',
fontFamily: 'Roboto-Medium',
marginLeft: 10,
fontSize: 18,
},
listValue: {
fontFamily: 'Roboto-Regular',
marginTop: 4,
color: 'black',
marginLeft: 10,
fontSize: 14,
},
listImage: {
alignSelf: 'center',
height: 25,
width: 25,
margin: 10
},
listimgArrow: {
// flex: 1,
// flexDirection:'row',
alignSelf: 'center',
height: 25,
width: 25,
margin: 10
},
listVal: {
borderWidth: 1,
borderRadius: 10,
color: 'darkgreen',
borderColor: 'white',
backgroundColor: 'white',
fontWeight: 'bold'
},
});
export default AtmBranchTypeSelect;
From the code I have, headerRight will be displayed in all scenarios. consider I have a scenario like based on state value I have to enable/disable headerRight Button .
for example this.state.stBool? headerRight:(.....) : null
I have to render in this way.Please guide me to achieve this.
You could nest the navigation options inside the render and toggle it based on the state value. Haven't tested and not positively on performace. Hope it helps.
import React, { Component } from "react";
import {
View,
TextInput,
Text,
TouchableOpacity,
TouchableHighlight,
StyleSheet,
AsyncStorage,
BackHandler,
Image,
FlatList,
Dimensions,
TouchableWithoutFeedback
} from "react-native";
import i18n from "../../i18n/i18n.js";
import { colors } from "../../constants/colors.js";
import Storage from "../../utils/AsyncStorage.js";
class AtmBranchTypeSelect extends Component {
// Render callBack
constructor(props) {
super(props);
this.state = {
data: [],
stBool: false
};
}
async componentWillMount() {
BackHandler.addEventListener("hardwareBackPress", () =>
this.props.navigation.goBack()
);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", () =>
this.props.navigation.goBack()
);
}
_renderList = ({ item }) => {
return (
<TouchableWithoutFeedback onPress={event => this._selectedItem(item.key)}>
<View style={styles.listRowContainer}>
<View style={styles.listinside1Container}>
<Image style={styles.listImage} source={item.icon} />
<View
style={styles.listContainer}
onPress={event => this._selectedItem(item.text)}
>
<Text style={styles.listHeader}>{item.header}</Text>
<Text style={styles.listValue}>{item.value}</Text>
</View>
</View>
<Image
style={styles.listimgArrow}
source={require("../../resources/toolbar/chevron_right_grey.png")}
/>
</View>
</TouchableWithoutFeedback>
);
};
// Render callBack
render() {
const { stBool } = this.state;
const navigationOptions = ({ navigation }) => ({
title: i18n.t("atmbranchpickHeader"),
headerRight: stBool ? (
<TouchableHighlight
onPress={() => {
navigation.navigate("home");
}}
>
<Image
style={{ marginRight: 20 }}
source={require("../../resources/toolbar/home_white.png")}
/>
</TouchableHighlight>
) : null,
headerTintColor: "white",
headerStyle: {
backgroundColor: colors.themeColor
// top: 30
}
});
return (
<View style={styles.mainWrapper}>
<FlatList data={this.state.data} renderItem={this._renderList} />
</View>
);
}
}