how can i change the options of my drawerNavigator with React Native when user is logged - react-native

I need to change the content of my DrawerNavigator once the user is logged.
Can someone help me, please?

You can make your custom DrawerNavigator and change its View or Content dynamically. Here is an example:
public static Routes = DrawerNavigator({
Main: {
screen: StackNavigator({
Home: { screen: Home },
Contents: { screen: Contents },
ContentList: { screen: ContentList },
}, stackConfig('Home'))
},
MessageInbox: { screen: MessageInbox },
UserInfo: { screen: UserInfo}
}, {
initialRouteName: 'Main',
drawerWidth: 300,
drawerPosition: Platform.OS == 'ios' ? 'left' : 'right',
contentComponent: (props: any) => (
<DrawerComponent properties={props} />
)
}
)
DrawerComponent.js:
import React from 'react'
import { View, Platform, Text, Image, ScrollView, TouchableOpacity, AsyncStorage } from 'react-native'
import { DrawerItems, NavigationActions } from 'react-navigation'
import Icon from 'react-native-vector-icons/Ionicons';
export default class DrawerComponent extends React.PureComponent {
constructor(props) {
super(props)
this.state = {
user: null,
avatarPic: 'avatars/0-1.png',
}
}
componentDidMount() {
this.fetchData()
}
fetchData = async () => {
let data = await AsyncStorage.getItem('UserData')
this.setState({ user: data })
}
render() {
let { user } = this.state
return (
<ScrollView contentContainerStyle={{ flex: 1 }}>
<View style={{ width: '100%', height: '30%', backgroundColor: 'white' }}>
<Image
style={{ width: 50, height: 50 }}
source={{ uri: this.state.avatarPic }}
/>
<TouchableOpacity
onPress={() => {
this.props.properties.navigation.navigate('UserInfo')
}}
style={{ marginTop: 10 }}>
<Text>{user.name ? user.name : 'New User'}</Text>
</TouchableOpacity>
</View>
<DrawerItems {...this.props.properties} />
</ScrollView>
)
}
}
I hope it help you.

Related

How can I show the Drawer (SideMenu) on any screen except in the login using React Native?

I had several problems trying to achieve this.
The sidemenu is not displayed on the Login screen, but in the Home component yes(this is fine).
But if I go back to the login component (by clicking on the menu navigation item), drawer is now shown from the login (It only must be showed on the Home component). I do not know why the template that I have to put in the drawer is not shown, by default the routes that I have created appear and with this the problem occurs (I am trying to put a template in the sidemenu)..
How can I fix this?
this is my code:
app.js
import React from "react";
import { StyleSheet, View } from "react-native";
import UserNavigation from "./app/navigation/UserNavigation";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return <UserNavigation />;
}
}
userNavigation.js
import React from "react";
import {
Platform,
StyleSheet,
Text,
View,
SafeAreaView,
ScrollView,
Dimensions,
Image
} from "react-native";
import { createDrawerNavigator, DrawerItems } from "react-navigation-drawer";
import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import { Icon } from "native-base";
import LoginScreen from "../screens/login/Login";
import HomeScreen from "../screens/home/Home";
const { width } = Dimensions.get("window");
const CustomDrawerNavigation = props => {
return (
<SafeAreaView style={{ flex: 1 }}>
<View
style={{
height: 250,
backgroundColor: "#fff",
opacity: 0.9
}}
>
<View
style={{
height: 200,
backgroundColor: "Green",
alignItems: "center",
justifyContent: "center"
}}
>
<Image
source={require("../../assets/img/logo.webp")}
style={{ resizeMode: "contain", width: "100%" }}
/>
</View>
<View
style={{
height: 50,
backgroundColor: "Green",
alignItems: "center",
justifyContent: "center"
}}
></View>
</View>
<ScrollView>
<DrawerItems {...props} />
</ScrollView>
<View style={{ left: 20, bottom: 20 }}>
<View style={{ flexDirection: "row" }}>
<View
onPress={() => props.navigation.navigate("Login")}
style={{
flexDirection: "row",
alignItems: "flex-start",
justifyContent: "center",
marginRight: 15
}}
>
<Icon
type="MaterialCommunityIcons"
name="logout"
style={{ fontSize: 24 }}
onPress={() => props.navigation.navigate("Login")}
/>
<Text>Salir</Text>
</View>
</View>
</View>
</SafeAreaView>
);
};
const DrawerStack = createStackNavigator({
Home: HomeScreen
});
const DrawerNavigation = createDrawerNavigator({
Home: {
name: "Home",
screen: HomeScreen
},
Login: {
name: "Cerrar Sesión",
screen: LoginScreen
}
});
const AppNavigator = createSwitchNavigator(
{
App: DrawerNavigation,
Login: {
screen: LoginScreen
}
},
{
initialRouteName: "Login",
drawerPosition: "left",
I have another problem and I don't know why the template (CustomDrawerNavigation) I have to put in the drawer is not shown.
contentComponent: CustomDrawerNavigation,
drawerOpenRoute: "DrawerOpen",
drawerCloseRoute: "DrawerClose",
drawerToggleRoute: "DrawerToggle",
drawerWidth: (width / 3) * 2
}
);
const AppContainer = createAppContainer(AppNavigator);
export default AppContainer;
login.js
import React, { Component } from "react";
import { View } from "react-native";
import { Button, Text } from "native-base";
export default class Login extends Component {
constructor() {
super();
this.state = {};
}
handlerLogin = async () => {
this.props.navigation.navigate("Home");
};
render() {
return (
<View>
<Text>Login</Text>
<Button block button onPress={() => this.handlerLogin()}>
<Text>Go to home</Text>
</Button>
<Text>Login</Text>
</View>
);
}
}
home.js
import React, { Component } from "react";
import { StyleSheet } from "react-native";
import { StatusBar } from "react-native";
import {
Container,
Header,
Title,
Left,
Icon,
Right,
Button,
Body,
Content,
Text,
Card,
CardItem
} from "native-base";
export default class Home extends Component {
constructor() {
super();
this.state = {
loading: false
};
}
closeDrawer = () => {
this.drawer._root.close();
};
openDrawer = () => {
this.drawer._root.open();
};
render() {
return (
<Container>
<Header>
<Left>
<Button
transparent
onPress={() => this.props.navigation.openDrawer()}
>
<Icon name="menu" />
</Button>
</Left>
<Body>
<Title>HomeScreen</Title>
</Body>
<Right />
</Header>
<Content padder>
<Card>
<CardItem>
<Body>
<Text>Home</Text>
</Body>
</CardItem>
</Card>
</Content>
</Container>
);
}
}
For this you can create two Navigators.
Advantages:
1. After login he cant get back to Login screen if he press back
2. Side Drawer wont be visible in Login Page
Imports we need:
import { createAppContainer, createSwitchNavigator } from 'react-navigation'; import { createStackNavigator } from 'react-navigation-stack'; import { createDrawerNavigator } from 'react-navigation-drawer';
Login Stack:
const LoginStack = createStackNavigator(
{
Login: {
screen: Login,
navigationOptions: {
title: 'Login',
headerLeft: null,
header: null
}
},
forgotPassword: {
screen: ForgotPassword,
navigationOptions: {
title: 'Forgot Password'
}
}
},
{
initialRouteName: 'Login',
} );
Home Page Stack:
const homePageBottomNavigationStack = createStackNavigator(
{
Home: {
screen: Login,
navigationOptions: {
title: 'Login',
headerLeft: null,
header: null
},
},
{
initialRouteName: 'Home',
} )
Drawer Navigator:
const PostLoginStack = createDrawerNavigator(
{
Home: {
screen: homePageBottomNavigationStack
}
} );
Switch Navigator:
const switchNavigator = createSwitchNavigator(
{
LoginStack: LoginStack,
PostLoginStack: PostLoginStack
},
{ headerMode: "none", initialRouteName: "LoginStack" } );
const AppContainer = createAppContainer(switchNavigator);
package.json:
"react": "16.9.0",
"react-native": "0.61.5",
"react-native-gesture-handler": "^1.5.1",
"react-native-paper": "^3.2.1",
"react-native-reanimated": "^1.4.0",
"react-navigation": "^4.0.10",
"react-navigation-drawer": "^2.3.3",
"react-navigation-material-bottom-tabs": "^2.1.5",
"react-navigation-stack": "^1.10.3"
For Having a custom drawer component, make this change:
const PostLoginStack = createDrawerNavigator(
{
Home: {
screen: homePageBottomNavigationStack
}
},
{
contentComponent: YourCustomDrawerComponent
}
);
You will need to create two navigators one for the Login and one for the App and then wrap them into a SwitchNavigator
So
Login = StackNavigator
App = DrawerNavigator
and Login and App together into a SwitchNavigator
You can refer this article
https://medium.com/building-with-react-native/routing-in-react-native-apps-and-how-to-configure-your-project-with-react-navigation-library-d8d58005bfe9

Could not navigate to another screen when using token in React Native

I'm currently developing an app using react native, right now my issue is that i couldn't navigate to main screen after login. Below is my code.
This is App.js (EDITED)
import React from 'react';
import { Loading } from './components/common/';
import TabNavigator from './screens/TabNavigator';
import AuthNavigator from './screens/AuthNavigator';
import MainNavigator from './screens/MainNavigator';
import deviceStorage from './services/deviceStorage.js';
import { View, StyleSheet } from 'react-native';
export default class App extends React.Component {
constructor() {
super();
this.state = {
token: '',
loading: true
}
this.newJWT = this.newJWT.bind(this);
this.deleteJWT = deviceStorage.deleteJWT.bind(this);
this.loadJWT = deviceStorage.loadJWT.bind(this);
this.loadJWT();
}
state = {
isLoadingComplete: false,
};
newJWT(token){
this.setState({
token: token
});
}
render() {
if (this.state.loading) {
return (
<Loading size={'large'} />
);
} else if (!this.state.token) {
return (
<View style={styles.container}>
<AuthNavigator screenProps = {{setToken:this.newJWT}} />
</View>
);
} else if (this.state.token) {
return (
<View style={styles.container}>
<MainNavigator screenProps = {{token: this.state.token,
deleteJWT:this.deleteJWT,}} />
</View>
);
}
}
}
This is Login.js (EDITED-v2)
import React, { Component, Fragment } from 'react';
import { Text, View, StyleSheet, ImageBackground, KeyboardAvoidingView,
TouchableOpacity, TextInput, Alert } from 'react-native';
import axios from 'axios';
import deviceStorage from '../services/deviceStorage';
class Login extends Component {
constructor(props) {
super(props)
this.state = {
username: '',
password: '',
error: '',
loading: false
};
this.loginUser = this.loginUser.bind(this);
this.onLoginFail = this.onLoginFail.bind(this);
}
loginUser() {
const { username, password, password_confirmation } = this.state;
this.setState({ error: '', loading: true });
// NOTE Post to HTTPS only in production
axios.post("http://192.168.1.201:8000/api/login",{
username: username,
password: password
})
.then((response) => {
console.log('response',response)
deviceStorage.saveKey("token", response.data.token);
console.log(response.data.token);
this.props.newJWT(response.data.token);
})
.catch((error) => {
const status = error.response.status
if (status === 401) {
this.setState({ error: 'username or password not recognised.' });
}
this.onLoginFail();
//console.log(error);
//this.onLoginFail();
});
}
onLoginFail() {
this.setState({
error: 'Login Failed',
loading: false
});
}
render() {
// other codes here
}
const styles = StyleSheet.create({
// other codes here
});
export { Login };
This is TabNavigator.js (Added)
import React from 'react';
import { Text } from 'react-native';
import { createMaterialTopTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import Profile from '../screens/Profile';
const TabNavigator = createMaterialTopTabNavigator(
{
Profile: {
screen: props => <Profile {...props.screenProps} />,
navigationOptions: {
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-person' : 'ios-person'} //TODO change to focused
icon
size={30}
style={{ color: tintColor }}
/>
),
}
},
},
{ initialRouteName: 'Profile',
tabBarPosition: 'top',
swipeEnabled: false,
animationEnabled: true,
lazy: true,
tabBarOptions: {
showLabel: false,
showIcon: true,
activeTintColor: 'orange',
inactiveTintColor: 'orange',
style: {
backgroundColor: '#555',
},
indicatorStyle: {
color: '#orange'
}
}
}
);
const screenTitles = {
Profile: { title: 'Profiler' },
Home: { title: 'Home' },
};
TabNavigator.navigationOptions = ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
const headerTitle = screenTitles[routeName].title;
const tabBarVisible = false;
return {
headerTitle,
tabBarVisible
};
};
export default TabNavigator;
This is my AuthLoadingScreen.js
import React from 'react';
import { View } from 'react-native';
import { Login } from '../screens/Login';
class AuthLoadingScreen extends React.Component {
constructor(props){
super(props);
this.state = {
showLogin: true
};
this.whichForm = this.whichForm.bind(this);
this.authSwitch = this.authSwitch.bind(this);
}
authSwitch() {
this.setState({
showLogin: !this.state.showLogin
});
}
whichForm() {
if(this.state.showLogin){
return(
<Login newJWT={this.props.newJWT} authSwitch={this.authSwitch} />
);
} else {
}
}
render() {
return(
<View style={styles.container}>
{this.whichForm()}
</View>
);
}
}
export default AuthLoadingScreen;
const styles = {
// style codes here
};
Lastly, this is my Profile.js
import React, { Component } from 'react';
import { View, Text, TouchableOpacity, Alert, Platform } from
'react-native';
import { Button, Loading } from '../components/common/';
import axios from 'axios';
export default class Profile extends Component {
constructor(props){
super(props);
this.state = {
loading: true,
email: '',
name: '',
error: ''
}
}
componentDidMount(){
this.onLocationPressed();
const headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.props.token
};
axios({
method: 'GET',
url: 'http://192.168.1.201:8000/api/user',
headers: headers,
}).then((response) => {
console.log('response',response)
console.log('response2',this.props.token)
this.setState({
email: response.data.user.email,
name: response.data.user.name,
loading: false
});
}).catch((error) => {
console.log(error);
this.setState({
error: 'Error retrieving data',
loading: false
});
});
}
render() {
const { container, emailText, errorText } = styles;
const { loading, email, name, error } = this.state;
if (loading){
return(
<View style={container}>
<Loading size={'large'} />
</View>
)
} else {
return(
<View style={container}>
<View>
<Text style={emailText}>Your email: {email}</Text>
<Text style={emailText}>Your name: {name}</Text>
</View>
<Button onPress={this.props.deleteJWT}>
Log Out
</Button>
</View>
);
}
}
}
const styles = {
// style codes here
};
I've fixed the previous problem that couldn't start the app. Right now i can see the login screen, but when i pressed login, there's a yellow box that indicates some problem. I've included the screenshot below.
Lastly i've added the deviceStorage.js
deviceStorage.js
import { AsyncStorage } from 'react-native';
const deviceStorage = {
async saveKey(key, valueToSave) {
try {
await AsyncStorage.setItem(key, valueToSave);
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
},
async loadJWT() {
try {
const value = await AsyncStorage.getItem('token');
if (value !== null) {
this.setState({
token: value,
loading: false
});
} else {
this.setState({
loading: false
});
}
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
},
async deleteJWT() {
try{
await AsyncStorage.removeItem('token')
.then(
() => {
this.setState({
token: ''
})
}
);
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
}
};
export default deviceStorage;
Before navigate
After navigate
This is my setup. It works like a charm. Sorry if it's a bit messy. I removed some stuff for clarity and I may have missed something:
App.js
import React from 'react';
import { Platform, StatusBar, StyleSheet, View } from 'react-native';
import { Asset, Font, Icon } from 'expo';
import { ENDPOINT, USER_TYPE } from './src/config'
import { Loading } from './src/components/common/';
import deviceStorage from './src/services/deviceStorage.js';
import TabNavigator from './src/TabNavigator';
import AuthNavigator from './src/AuthNavigator';
import MainNavigator from './src/MainNavigator';
import globalStyles from './src/globalStyles';
import './ReactotronConfig';
export default class App extends React.Component {
constructor() {
super();
this.state = {
jwt: '',
loading: true,
};
this.newJWT = this.newJWT.bind(this);
this.deleteJWT = deviceStorage.deleteJWT.bind(this);
this.loadJWT = deviceStorage.loadJWT.bind(this);
this.loadJWT();
}
state = {
isLoadingComplete: false,
};
newJWT(jwt) {
this.setState({
jwt: jwt
});
}
render() {
if (this.state.loading) {
return (
<Loading size={'large'} />
);
} else if (!this.state.jwt) {
//console.log(this.props, '<=== app.js');
return (
<View style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
<AuthNavigator screenProps={{setToken: this.newJWT }} />
</View>
);
} else {
return (
<View style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
<MainNavigator
screenProps={{ jwt: this.state.jwt,
deleteToken: this.deleteJWT,
}}
/>
</View>
);
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
justifyContent: 'center',
},
});
AuthNavigator.js
import React from 'react';
import { createAppContainer, createBottomTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import AuthScreen from './screens/AuthScreen';
const AuthNavigator = createBottomTabNavigator(
{
Auth: (props) => {
return <AuthScreen {...props.screenProps} />;
}
},
{ initialRouteName: 'Auth',
tabBarOptions: {
showLabel: false,
activeBackgroundColor: '#eee',
}
}
);
export default createAppContainer(AuthNavigator);
MainNavigator.js
import React from 'react';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import TabNavigator from './TabNavigator';
const MainNavigator = createStackNavigator({
Main: TabNavigator },
{
initialRouteName: 'Main',
defaultNavigationOptions: {
headerTitleStyle: {
fontSize: 20,
textTransform: 'uppercase'
}
}
});
export default createAppContainer(MainNavigator);
TabNavigator.js
import React from 'react';
import { Text } from 'react-native';
import { createMaterialTopTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import IconBadge from 'react-native-icon-badge';
import ProfileScreen from './screens/ProfileScreen';
import NotificationsScreen from './screens/NotificationsScreen';
import HomeStackNavigator from './HomeStackNavigator';
import CartStackNavigator from './CartStackNavigator';
import QuotesStackNavigator from './QuotesStackNavigator';
import InitialRoute from './InitialRoute';
const TabNavigator = createMaterialTopTabNavigator(
{
Profile: {
screen: props => <ProfileScreen {...props.screenProps} />,
navigationOptions: {
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-person' : 'ios-person'} //TODO change to focused icon
size={30}
style={{ color: tintColor }}
/>
),
}
},
Home: HomeStackNavigator,
Quotes: QuotesStackNavigator,
Notifications: { screen: props => <NotificationsScreen {...props.screenProps} />,
navigationOptions: ({ screenProps }) => ({
tabBarIcon: ({ tintColor, focused }) => (
<IconBadge
MainElement={
<Ionicons
name={focused ? 'ios-notifications' : 'ios-notifications'}
size={30}
style={{ color: tintColor }}
/>
}
BadgeElement={
<Text style={{ color: '#FFFFFF' }}>{screenProps.unreadMessagesCount}</Text>
}
IconBadgeStyle={{ width: 15,
height: 15,
position: 'absolute',
top: 1,
left: -6,
marginLeft: 15,
backgroundColor: 'red' }}
Hidden={screenProps.unreadMessagesCount === 0}
/>
)
})
},
Cart: CartStackNavigator,
},
{ initialRouteName: 'Profile',
tabBarPosition: 'top',
swipeEnabled: false,
animationEnabled: true,
lazy: true,
tabBarOptions: {
showLabel: false,
showIcon: true,
activeTintColor: 'orange',
inactiveTintColor: 'orange',
style: {
backgroundColor: '#555',
},
indicatorStyle: {
color: '#orange'
}
}
}
);
const screenTitles = {
Profile: { title: 'Hola Maestro' },
Home: { title: 'Selecciona la Categoría' },
Quotes: { title: 'Mi Historial de Cotizaciones' },
Notifications: { title: 'Notificaciones' },
Cart: { title: 'Mi Pedido' },
};
TabNavigator.navigationOptions = ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
const headerTitle = screenTitles[routeName].title;
const tabBarVisible = false;
return {
headerTitle,
tabBarVisible
};
};
export default TabNavigator;
Login.js
import React, { Component, Fragment } from 'react';
import { Text, View, StyleSheet, ImageBackground, KeyboardAvoidingView } from 'react-native';
import axios from 'axios';
import Ionicons from 'react-native-vector-icons/Ionicons';
//import Pusher from 'pusher-js/react-native';
import { ENDPOINT, USER_TYPE } from '../config'
import deviceStorage from '../services/deviceStorage';
import { Input, TextLink, Loading, Button } from './common';
import Header from '../components/Header';
class Login extends Component {
constructor(props){
super(props);
this.state = {
username: '',
password: '',
error: '',
loading: false
};
this.pusher = null; // variable for storing the Pusher reference
this.my_channel = null; // variable for storing the channel assigned to this user
this.loginUser = this.loginUser.bind(this);
}
loginUser() {
const { username, password, password_confirmation } = this.state;
axios.post(`${ENDPOINT}/login`, {
user: {
login: username,
password: password
}
})
.then((response) => {
deviceStorage.saveKey("id_token", response.headers.authorization);
this.props.newJWT(response.headers.authorization);
//this.setPusherData();
})
.catch((error) => {
this.onLoginFail();
});
}
onLoginFail() {
this.setState({
error: 'Usuario o contraseña incorrecta',
loading: false
});
}
}
render() {
const { username, password, error, loading } = this.state;
const { container, form, section, errorTextStyle, iconContainer, inputContainer, titleText } = styles;
return (
<View style={container}>
<Header title="¡Bienvenido Amigo Maestro!" />
<View style={form}>
<ImageBackground source={require('./cemento-login.jpg')} style={{ flex: 1, marginBottom: 30 }}>
<View style={{marginTop: 120}}>
<Text style={titleText}>INICIAR SESIÓN</Text>
<View style={section}>
<View style={iconContainer}>
<Ionicons
name={'ios-person'}
size={26}
style={{ color: '#fff', alignSelf: 'center' }}
/>
</View>
<View style={inputContainer}>
<Input
placeholder="Usuario"
value={username}
onChangeText={username => this.setState({ username })}
/>
</View>
</View>
<View style={section}>
<View style={iconContainer}>
<Ionicons
name={'ios-lock'}
size={26}
style={{ color: '#fff', alignSelf: 'center' }}
/>
</View>
<View style={inputContainer}>
<Input
secureTextEntry
placeholder="Contraseña"
value={password}
onChangeText={password => this.setState({ password })}
/>
</View>
</View>
</View>
</ImageBackground>
</View>
<KeyboardAvoidingView
behavior="padding"
keyboardVerticalOffset={30}
>
<TextLink style={{ }} onPress={this.props.formSwitch}>
Aún no estas registrado? Regístrate
</TextLink>
<TextLink style={{ }} onPress={this.props.forgotPassword}>
Olvidaste tu contraseña?
</TextLink>
<Text style={errorTextStyle}>
{error}
</Text>
{!loading ?
<Button onPress={this.loginUser}>
Ingresar
</Button>
:
<Loading size={'large'} />}
</KeyboardAvoidingView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
form: {
flex: 0.8
},
section: {
flexDirection: 'row',
backgroundColor: '#eee',
borderRadius: 3,
marginTop: 10,
height: 40,
marginLeft: '10%',
marginRight: '10%',
},
titleText: {
color: '#fff',
alignSelf: 'center',
fontSize: 20,
marginBottom: 10
},
errorTextStyle: {
alignSelf: 'center',
fontSize: 18,
color: 'red'
},
iconContainer: {
flex: 0.1,
height: 40,
borderRadius: 3,
alignSelf: 'center',
justifyContent: 'center',
backgroundColor: 'orange',
},
inputContainer: {
flex: 0.8,
alignSelf: 'flex-start',
marginLeft: -70,
}
});
export { Login };
Inside App.js you never change loading to false so the render method never gets to any of the other conditions. Once you have received the token you need to update state and change loading.

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 navigate between screens from any js class that is not inside App.js in React Native

It's very easy to navigate from one screen to another that is inside App.js class. What I have done is made three classes : App.js, SearchList.js and Detail.js. But i am facing issue that how to navigate from searchList.js to Detail.js on click any view inside searchList.js class. Should i use StackNavigator again in searchList.js or declare all classes in App.js ?
App.js
import React from 'react';
import { Image,Button, View, Text ,StatusBar,StyleSheet,Platform,TouchableOpacity,ImageBackground,Picker,Alert,TouchableHighlight} from 'react-native';
import { StackNavigator,DrawerNavigator,DrawerItems } from 'react-navigation';
import {Constants} from "expo";
import SearchList from './classes/SearchList';
import Detail from './classes/Detail';
const DrawerContent = (props) => (
<View>
<View
style={{
backgroundColor: '#f50057',
height: 160,
alignItems: 'center',
justifyContent: 'center',
}}
>
<Text style={{ color: 'white', fontSize: 30 }}>
Header
</Text>
</View>
<DrawerItems {...props} />
</View>
)
class HomeScreen extends React.Component {
static navigationOptions = {
drawerLabel: 'Home',
drawerIcon: ({ tintColor }) => (
<Image
source={require('./images/crown.png')}
style={[styles.icon, {tintColor: '#f50057'}]}
/>
),
};
constructor(){
super();
this.state={PickerValueHolder : ''}
}
GetSelectedPickerItem=()=>{
Alert.alert(this.state.PickerValueHolder);
}
render() {
return (
<ImageBackground source={require('./images/green.png')} style={styles.backgroundImage} >
<TouchableOpacity onPress={() =>this.props.navigation.navigate('DrawerOpen')}>
<Image
source={require('./images/menu-button.png')}
style={styles.imagesStyle}
/>
</TouchableOpacity>
<View style={styles.columnContainer}>
<TouchableHighlight style={styles.search} underlayColor='#fff' onPress={() => this.props.navigation.navigate('SearchList')}>
<Text style={styles.searchText}>Search Hotels</Text>
</TouchableHighlight>
</View>
</ImageBackground >
);
}
}
class DetailsScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button
title="Go to Details... again"
onPress={() => this.props.navigation.navigate('Details')}
/>
</View>
);
}
}
const styles = StyleSheet.create({
backgroundImage: {
flex: 1,
width: null,
height: null,
marginTop: Constants.statusBarHeight,
},
search:{
marginTop:20,
paddingTop:15,
borderRadius:8,
borderColor: '#fff'
},
searchText:{
color:'#fff',
textAlign:'center',
}
// backgroundColor: '#ef473a', // app color
});
const HomeStack = StackNavigator({
Home: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => ({
header: null,
})
},
SearchList: { screen: SearchList },
Detail: { screen: Detail},
});
const RootStack = DrawerNavigator(
{
Home: {
screen: HomeStack,
},
DetailsScreen: {
screen: DetailsScreen,
},
},
{
initialRouteName: 'Home',
}
);
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
SearchList.js
import React, { Component } from 'react';
import { StyleSheet, Platform, View, ActivityIndicator, FlatList, Text, Image, Alert, YellowBox,ImageBackground } from 'react-native';
import { StackNavigator,} from 'react-navigation';
import Detail from './classes/Detail';
export default class SearchList extends Component {
constructor(props) {
super(props);
this.state = {isLoading: true}
YellowBox.ignoreWarnings([
'Warning: componentWillMount is deprecated',
'Warning: componentWillReceiveProps is deprecated',
]);
}
GetItem (flower_name) {
Alert.alert(flower_name);
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: .0,
width: "100%",
backgroundColor: "#000",
}}
/>
);
}
webCall=()=>{
return fetch('https://reactnativecode.000webhostapp.com/FlowersList.php')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson
}, function() {
// In this block you can do something with new state.
});
})
.catch((error) => {
console.error(error);
});
}
componentDidMount(){
this.webCall();
}
render() {
if (this.state.isLoading) {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<ActivityIndicator size="large" />
</View>
);
}
return (
<View style={styles.MainContainer}>
<FlatList
data={ this.state.dataSource }
ItemSeparatorComponent = {this.FlatListItemSeparator}
renderItem={({item}) =>
<ImageBackground source= {{ uri: item.flower_image_url }} style={styles.imageView}
onPress={() => this.props.navigation.navigate('Detail')}>
</ImageBackground>
}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
MainContainer :{
justifyContent: 'center',
flex:1,
margin: 5,
marginTop: Constants.statusBarHeight , //(Platform.OS === 'ios') ? 20 : 14,
},
imageView: {
width: '100%',
height: 220 ,
margin: 7,
borderRadius : 40,
},
});
const HomeStack = StackNavigator({
Detail: { screen: Detail},
});
export default class App extends React.Component {
render() {
return <HomeStack />;
}
}
Any help would be appreciable.
To navigate to any screen you need to have a navigation object. Navigation object can be provided in two ways
By declaring it in StackNavigator
By explicitly passing it as a prop to some other screen
If you use the first approach, and you need to navigate from SecondScreen to ThirdScreen, both of your screens should be declared in the StackNavigator first, only then navigation will be successful.
If you are using any trivial component ( such as a modal box ) to navigate to another screen, all you need to do is pass the navigation props (this.props.navigation) to the modal box component and use the props to navigate to another screen. The only requirement here being, this.props.navigation should be available in the class where the modal box component is loaded.
EDIT
As requested, here is the snippet
const App = StackNavigator({
FirstScreen: { screen: FirstScreen},
SecondScreen: { screen: SecondScreen},
ThirdScreen: { screen: ThirdScreen}
})
export default App;
In your SecondScreen, declare an object const { navigate } = this.props.navigation; and on a button click, use this object to navigate to another screen navigate("ThirdScreen");
Regarding the second approach, if your component is a modal, you can pass the navigate object as - <Modal navigation={navigate} /> and in the modal component you can use it as this.props.navigation("ThirdScreen");
Hope it clarifies now.
Support we have js named SecondScreen.js at the same directory level as App.js then we should import it like this in App.js
import SecondScreen from './SecondScreen';
It worked for me. Hope this helps to you too.
I think you are trying to implement the functionality of a stack navigator.
Go to React-Navigation-Docs. In stack navigator you can make stack of screens, and navigate from one to another. Inside index.js :
import { StackNavigator, TabNavigator } from "react-navigation";
import SplashScreen from "./src/screens/start/splash";
import LoginScreen from "./src/screens/start/login";
import DomainScreen from "./src/screens/start/domain";
const App = StackNavigator(
{
Splash: {
screen: SplashScreen,
},
Domain: {
screen: DomainScreen,
},
Login: {
screen: LoginScreen,
},
Tabs: {
screen: HomeTabs,
}
},
{
initialRouteName: "Splash",
}
);
AppRegistry.registerComponent("app_name", () => App);
then you can navigate to any of these screens using this.props.navigation.navigate("ScreenName")

Header with gradient image overlay

I am trying to add a header with a gradient image overlay to an app I am making.
The below code has been trimmed down and simplified in the hope to make it meaningful to you.
The header should be visible on all screens, where some screens show the back button and only the front screen show a logo and settings to the right.
How can I solve that?
import { TabNavigator, StackNavigator } from 'react-navigation';
import React, { Component } from 'react';
import Example from '../components/example';
const navContainer = (Comp, options) => {
return StackNavigator({
Main: {
screen: Comp,
navigationOptions: options
},
S1: {
screen: Example
},
S2: {
screen: Example,
navigationOptions: ({ navigation }) => {
return {
headerTitle: <Example {...navigation.state.params} />,
headerStyle: {
backgroundColor: 'white'
}
}
}
},
S3: {
screen: Example,
navigationOptions: ({ navigation }) => {
return {
headerTitle: <Example {...navigation.state.params} />,
headerStyle: {
backgroundColor: 'white'
}
}
}
},
S4: {
screen: Example,
navigationOptions: ({ navigation }) => {
return {
headerTitle: <Example {...navigation.state.params} />,
headerStyle: {
backgroundColor: 'white'
}
}
}
}
},
{
cardStyle: {
backgroundColor: 'green'
}
})
}
const navOptions = title => {
return {
headerTitle: title,
headerBackTitle: null,
headerStyle: {
backgroundColor: 'transparent'
}
}
}
const NavTab = TabNavigator(
{
M1: {
screen: navContainer(Example, navigation => ({
headerTitle: <Example />,
headerRight: <Example { ...navigation } />,
headerStyle: {
backgroundColor: 'transparent'
}
}))
},
M2: {
screen: navContainer(Example, navOptions('M2'))
},
M3: {
screen: navContainer(Example, navOptions('M3'))
},
M4: {
screen: navContainer(Example, navOptions('M4'))
}
},
{
tabBarPosition: 'bottom',
lazy: true,
tabBarOptions: {
inactiveBackgroundColor: 'white',
activeBackgroundColor: 'white'
}
}
);
export default NavTab;
The example component:
import React, { Component } from 'react';
import { StyleSheet, View, Text } from 'react-native';
export default class Example extends Component {
static style = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})
render () {
return (
<View style={ Example.style.container }>
<Text>hello</Text>
</View>
);
}
}
My first attempt was to overwrite Header._renderHeader, but the status bar was still not covered.
The final solution is below the <hr />.
import React from 'react';
import { Header } from 'react-navigation';
import { StyleSheet, View, StatusBar, Image } from 'react-native';
import img_gradient from '../images/headerbg.png';
const style = StyleSheet.create({
header: {
flexDirection: 'row'
},
img: {
width: '100%',
height: '100%',
resizeMode: 'stretch'
}
});
export default class NavHeader extends Header {
_renderHeader (props) {
const left = this._renderLeft(props);
const right = this._renderRight(props);
const title = this._renderTitle(props, {
hasLeftComponent: left !== null,
hasRightComponent: right !== null
});
return (
<View key={ `scene_${ props.scene.key }` } style={ [StyleSheet.absoluteFill, style.header] }>
<StatusBar barStyle="light-content" />
<Image source={ img_gradient } style={ style.img }>
{ title }
{ left }
{ right }
</Image>
</View>
);
}
}
Here's how I solved it, by putting my root element inside BgImg: <BgImg><App /></BgImg>.
import React, { Component } from 'react';
import { StyleSheet, Image, StatusBar } from 'react-native';
import img_gradient from '../images/headerbg.png';
export default class BgImg extends Component {
static style = StyleSheet.create({
img: {
width: '100%',
height: '100%',
resizeMode: 'stretch'
}
})
render () {
return (
<Image source={ img_gradient } style={ BgImg.style.img }>
<StatusBar barStyle="light-content" />
{ this.props.children }
</Image>
);
}
}