'TypeError: Cannot read property 'state' of undefined' error' in react-native - react-native

I have created the header using defaultNavigationOptions The navigation bar contains Home, signup, login, create blog options. If the user has signed in then Login option should not be visible, instead, logout option should be enabled. I'm using AsyncStorage to store the token.
App.js:
import React from 'react';
import { CreateBlog } from './app/views/CreateBlog.js';
import { BlogDetails } from './app/views/BlogDetails.js';
import { EditBlog } from './app/views/EditBlog.js';
import { DeleteBlog } from './app/views/DeleteBlog.js';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { Home } from './app/views/Home.js';
import { Login } from './app/views/Login.js';
import {
StyleSheet, Text, View, TextInput, TouchableHighlight, Alert, AsyncStorage
} from 'react-native';
import { Signup } from './app/views/Signup.js';
const AppNavigator = createStackNavigator(
{
CreateBlogRT: {
screen: CreateBlog
},
BlogDetailsRT: {
screen: BlogDetails
},
EditBlogRT: {
screen: EditBlog
},
DeleteBlogRT: {
screen: DeleteBlog
},
SignupRT: {
screen: Signup
},
LoginRT: {
screen: Login
},
HomeRT: {
screen: Home,
},
},
{
initialRouteName: 'HomeRT',
defaultNavigationOptions: ({ navigation }) => ({
header: <View style={{
flexDirection: "row",
height: 80,
backgroundColor: '#f4511e', fontWeight: 'bold'
}} >
<TouchableHighlight onPress={() => navigation.navigate('SignupRT')}>
<Text > SignUp</Text>
</TouchableHighlight>
<TouchableHighlight onPress={() => navigation.navigate('CreateChapterRT')}>
<Text > CreateChapter</Text>
</TouchableHighlight>
<TouchableHighlight onPress={() => navigation.navigate('LoginRT')}>
<Text > Login</Text>
</TouchableHighlight>
//getting 'TypeError: Cannot read property 'state' of undefined'
{this.state.logged_in &&
<TouchableHighlight onPress={async () => {
await AsyncStorage.removeItem('token');
await AsyncStorage.removeItem('user_id');
}}>
<Text > Logout</Text>
</TouchableHighlight>
}
</View >
}),
},
}
);
const MyRoutes = createAppContainer(AppNavigator);
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { logged_in: false };
}
componentDidMount = async () => {
var logged_in = await AsyncStorage.getItem('token')
this.setState({ logged_in: false })
}
render() {
return (
<MyRoutes />
);
}
}
Now on clicking the logout button, it deletes the token. I want the logout button should be visible only if the user has logged in. In the same way login & signup options as well. (
const loggedin=AsyncStorage.getItem('token');if(userloggedin)
{showlogout:true;showlogin:false;showSignup:false}.
I don't know where to write the code. Thanks in advance.

after sign-in user you can set userloggedin true
AsyncStorage.setItem('userloggedin',JSON.stringfy(true)
or
AsyncStorage.setItem('userloggedin',Boolean(true))
then getItem
const logged-in = AsyncStorage.getItem('userloggedin')
if(loggedin){
showlogout=true
showlogin=false
showSignup=false
or if your are using state
this.setState({
showlogout:true,
showlogin:false,
showSignup:false})
}.

you can use react life-cycle for this work and also use global variable or state , like this
check this image
https://camo.githubusercontent.com/3beddc08b0e4b44fbdcef20809484f9044e091a2/68747470733a2f2f63646e2d696d616765732d312e6d656469756d2e636f6d2f6d61782f323430302f312a736e2d66746f7770305f565652626555414645434d412e706e67
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {logged_in: false};
}
componentDidMount=async() {
var logged_in = await AsyncStorage.getItem('token')
this.setState({logged_in: false})
}
render() {
const {logged_in} = this.state
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {logged_in}.</h2>
</div>
);
}
}

Related

Unable to run react-navigation functions on customised back button in React native

The function I am not able to run is the navigation functions in my example it's
this.this.props.navigation.goBack()
My Login File is posted below but the part with the problem is the short snippet
The error I am getting is: TypeError: undefined is not an object (evaluating 'LogIn.props.navigation')
First failed Snippet
static navigationOptions = {
headerLeft: () => (
<Button
onPress={()=>this.props.navigation.goBack()}
title="cancel"
color={colors.black}
/>
),
};
LogIn.js
import React, { Component } from 'react';
import { PropTypes } from 'prop-types';
import Icon from 'react-native-vector-icons/FontAwesome';
import colors from '../styles/colors';
import {
View,
Text,
ScrollView,
StyleSheet,
KeyboardAvoidingView,
Button
} from 'react-native';
import InputField from '../components/form/InputField';
import NexArrowButton from '../components/buttons/NextArrowButton';
import Notification from '../components/Notification';
export default class LogIn extends Component{
constructor(props){
super(props);
this.state ={
formValid:false,
validEmail:false,
emailAddress:'',
validPassword:false,
}
this.handleNextButton = this.handleNextButton.bind(this)
this.handleCloseNotification = this.handleCloseNotification.bind(this)
this.handleEmailChange = this.handleEmailChange.bind(this);
}
static navigationOptions = {
headerLeft: () => (
<Button
onPress={()=>this.props.navigation.goBack()}
title="cancel"
color={colors.black}
/>
),
};
handleNextButton(){
if(this.state.emailAddress === 'admin#mail.com'){
this.setState({formValid:true})
} else{
this.setState({formValid: false});
}
}
handleCloseNotification(){
this.setState({formValid:true });
}
handleEmailChange(email){
const emailCheckRegex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const { validEmail } = this.state;
this.setState({ emailAddress: email });
if (!validEmail) {
if (emailCheckRegex.test(email)) {
this.setState({ validEmail: true });
}
} else if (!emailCheckRegex.test(email)) {
this.setState({ validEmail: false });
}
}
handlePasswordChange(password){
const { validPassword } = this.state;
this.setState({ password });
if (!validPassword) {
if (password.length > 4) {
// Password has to be at least 4 characters long
this.setState({ validPassword: true });
}
} else if (password <= 4) {
this.setState({ validPassword: false });
}
}
render(){
const {formValid, validPassword} = this.state;
const showNotification = formValid ? false:true;
const background = formValid ? colors.green01 : colors.darkOrange;
const notificationMarginTop = showNotification ? 10:0;
return(
<KeyboardAvoidingView style={[{backgroundColor:background}, styles.wrapper] } behavior="padding">
<View style={styles.ScrollViewWrapper}>
<ScrollView style={styles.ScrollView}>
<Text style={styles.loginHeader}>Log In</Text>
<InputField
labelText= "Email Address"
labelTextSize={20}
labelColor={colors.white}
textColor={colors.white}
borderBottomColor={colors.white}
inputType="email"
customStyle={{marginBottom:30}}
onChangeText={this.handleEmailChange}
/>
<InputField
labelText= "Password"
labelTextSize={20}
labelColor={colors.white}
textColor={colors.white}
borderBottomColor={colors.white}
inputType="password"
customStyle={{marginBottom:30}}
/>
</ScrollView>
<View style={styles.nextButton}>
<NexArrowButton
// handleNextButton={this.handleNextButton}
handleNextButton={()=>this.props.navigation.goBack()}
/>
</View>
<View style={[styles.notificationWrapper, {marginTop:notificationMarginTop}]}>
<Notification
showNotification={showNotification}
handleCloseNotification={this.handleCloseNotification}
type="Error"
firstLine="Those credentials don't look right."
secondLine="Please try again."
/>
</View>
</View>
</KeyboardAvoidingView>
)
}
}
const styles = StyleSheet.create({
wrapper:{
display:'flex',
flex:1,
},
ScrollViewWrapper:{
marginTop:60,
flex:1,
},
ScrollView:{
paddingLeft:30,
paddingRight:30,
paddingTop:10,
flex:1,
},
loginHeader:{
fontSize:34,
color:colors.white,
fontWeight:'300',
marginBottom:40,
},
nextButton:{
position:'absolute',
right:20,
bottom:20,
},
notificationWrapper:{
position: 'absolute',
bottom:0,
zIndex:9
}
});
The most confusing part is that the second snippet below of Login.js works perfectly and it is essentially the same thing which means that I am getting the props right, but still get the error in customised back button.
Second working snippet
<View style={styles.nextButton}>
<NexArrowButton
// handleNextButton={this.handleNextButton}
handleNextButton={()=>this.props.navigation.goBack()}
/>
</View>
App.js
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View } from 'react-native';
import LoggedOut from './src/screens/LoggedOut';
import LogIn from './src/screens/LogIn';
import LoggedIn from './src/screens/LoggedIn';
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
const RootStack = createStackNavigator(
{
LoggedOut: LoggedOut,
LogIn: LogIn,
},
{
initialRouteName: 'LoggedOut',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
The error in more details
I really appreciate your help ! I am happy to provide more code if it makes it easier to debugg.
You have to change the static navigationOptions to following snippet if you want to access navigation properties in a static function:
static navigationOptions = ({ navigation }) => ({
headerLeft: () => (
<Button
onPress={()=>navigation.goBack()}
title="cancel"
color={colors.black}
/>
),
});
You don't need the this.props in this case ;) The static function does not have access to the this context so this.props will not work.

How to set initial state empty when try to navigation to other page react native

I have a problem when i try to navigation.navigate called RegisterPage but before that i try to typing anycharacter in field email and after that i click register button and back again, but the field is not empty
LoginContainer.js
import React, { Component, Fragment } from 'react';
import LoginComponent from '../../modules/LoginComponent/component/LoginComponent';
import axios from 'axios';
import { Toast } from '#ant-design/react-native';
class LoginContainer extends Component {
static navigationOptions = {
header: null,
}
constructor(props) {
super(props);
this.state = {
post : [],
email : '',
password : '' ,
showPassword: true,
}
}
onValueChange = (text, name) => {
this.setState({
[name] : text
});
}
getPostAPI = () => {
axios.get('http://10.2.62.212:3000/dataadmin')
.then((res) => {
this.setState ({
post : res.data,
})
})
.catch((err) => {
})
}
showPassword = () => {
const showPassword = !this.state.showPassword
this.setState({ showPassword });
}
onLoginPress = (event) => {
event.preventDefault();
const { post } = this.state;
if(!this.state.email.trim()) {
Toast.fail('Invalid Email', 1, undefined, false)
} else
if(!this.state.password.trim()) {
Toast.fail('Invalid Password', 1, undefined, false)
} else
if (post.find(e => `${e.email}${e.password}` === `${this.state.email}${this.state.password}` )) {
this.props.navigation.navigate('Dashboard');
} else
if (post.find(e => `${e.email}${e.password}` !== `${this.state.email}${this.state.password}` )) {
Toast.fail('Invalid Email or Password', 1, undefined, false)
}
}
onRegistPress = () => {
this.props.navigation.navigate('Register')
}
componentDidMount() {
this.getPostAPI();
}
render() {
return (
<Fragment>
<LoginComponent
navigation = {this.props.navigation}
change = {this.props.change}
onValueChange={this.onValueChange}
showPassword={this.showPassword}
onLoginPress={this.onLoginPress}
showPassword={this.state.showPassword}
onRegistPress = {this.onRegistPress}
/>
</Fragment>
);
}
}
export default LoginContainer;
LoginComponent.js
import React from 'react';
import { View, Text, TextInput, TouchableOpacity } from 'react-native';
import PropTypes from 'prop-types';
import { Button, Icon, Provider } from '#ant-design/react-native';
import styles from '../../../../assets/styles/default.style'
class LoginComponent extends React.Component {
static navigationOptions = {
header: null,
}
render() {
return (
<Provider >
<View style={styles.containerLogin}>
<View style={styles.parentViewStyleLogin}>
<Text style={styles.textHeaderStyle}> Merchant APP </Text>
<Text style={styles.textStyle}>Email</Text>
<View style={styles.inputContainer}>
<Icon style = {styles.styleIcon} name={"user"} color='black'/>
<TextInput
style={styles.textboxfield}
underlineColorAndroid='transparent'
onChangeText={(text) => this.props.onValueChange(text, 'email')}
placeholder = {'Input your email here'}
placeholderTextColor={'rgba(221,221,221,1)'}
/>
</View>
<Text style={[styles.textStyle, {marginTop: 20}] }> Password </Text>
<View style={styles.inputContainer}>
<Icon style = {styles.styleIcon} name={"key"} color='black'/>
<TextInput
style={styles.textboxfield}
secureTextEntry={this.props.showPassword}
underlineColorAndroid='transparent'
onChangeText={(text) => this.props.onValueChange(text, 'password')}
returnKeyType={'done'}
placeholder = {'Input your password here'}
placeholderTextColor={'rgba(221,221,221,1)'}
/>
</View>
<TouchableOpacity >
<Button style={[styles.buttonTextStyle, { borderRadius : 30 }]} onPress = {this.props.onLoginPress} >Login</Button>
</TouchableOpacity>
<TouchableOpacity onPress = {() => this.props.onRegistPress()} >
<Text style={styles.textDefault} >Dont have account ? Register</Text>
</TouchableOpacity>
</View>
</View>
</Provider>
);
}
}
export default LoginComponent
navigation
import { createStackNavigator } from 'react-navigation-stack';
import { createAppContainer } from 'react-navigation';
import LoginContainer from '../../app/LoginContainer/LoginContainer';
import DashboardContainer from '../../app/DashboardContainer/DashboardContainer';
import NotificationContainer from '../../app/NotificationContainer/NotificationContainer';
import TransactionContainer from '../../app/TransactionContainer/TransactionContainer'
import RegisterContainer from '../../app/RegisterContainer/RegisterContainer'
import DetailContainer from '../../app/DetailContainer/DetailContainer';
const AppNavigator = createStackNavigator(
{
Login: { screen: LoginContainer },
Dashboard: { screen: DashboardContainer },
Notification: { screen: NotificationContainer },
Transaction : { screen: TransactionContainer },
Register : { screen : RegisterContainer },
Detail : { screen : DetailContainer }
},
);
export default createAppContainer(AppNavigator);
this my ui
look after i try to type anycharacter and then directly click signup , and then click sigin again , and the field is not empty. i dont know how to fix it
there are 2 ways you can achieve this :
While you click on register in the DOnt have account text , then before navigation.navigate you can set the state of email to '' , like
onRegisterClick = () =>{
this.setSTate({email:''});//first this
this.props.navigation.navigate('Register');//then this
}
You can go back to the login page again by this.props.navigation.push('Login') rahther than navigation.navigate coz what navigate does is it calls the page from existing stack ,and push creates a new stack so values will be reset , so email will be null

this.props.navigation.toggedrawer is not a function-React Native 0.59.9 React Navigation 3.11.0

I have a requirement of using Redux in Tabnavigator which is inside of
an DrawerNavigator.Redux Portion is working fine, But I am unable to
open the drawer on click of a button but the drawer is visible on
swipe gesture.
I am providing my code:-
App.js:-
import * as React from 'react';
import {createAppContainer,createStackNavigator,createBottomTabNavigator} from 'react-navigation';
import RegisterStack from './routes/Register.route';
import SplashStack from './routes/Splash.route';
import Test from './src/pages/Test';
const AppNavigator = createStackNavigator(
{
Splash: SplashStack,
Register: RegisterStack,
StartTest :Test
},
{
initialRouteName: 'StartTest',
headerMode:'none'
});
let Navigation = createAppContainer(AppNavigator);
export default class App extends React.Component {
render() {
return (
<Navigation />
);
}
}
code in Test.js:-
import React from 'react';
import { View,StyleSheet,Text,SafeAreaView,Dimensions,Button } from 'react-native';
import {createAppContainer,createMaterialTopTabNavigator,createDrawerNavigator, DrawerActions} from 'react-navigation';
import ReferenceStack from './Reference';
import QuestionStack from './Question';
import { Provider, connect } from 'react-redux';
import { createStore, combineReducers } from 'redux';
function counter(state, action) {
if (typeof state === 'undefined') {
return 0;
}
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
let store = createStore(combineReducers({ count: counter }));
class DrawerLayout extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<SafeAreaView style={styles.container}>
<Text>{this.props.count}</Text>
<Button
title="Increment"
onPress={() => this.props.dispatch({ type: 'INCREMENT' })}
/>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: {
flex:1,
backgroundColor: "red",
}
});
let CounterContainer = connect(state => ({ count: state.count }))(ReferenceStack);
let StaticCounterContainer = connect(state => ({ count: state.count }))(QuestionStack);
let StaticCounterContainerDrawer = connect(state => ({ count: state.count }))(DrawerLayout);
const DrawerStack = createDrawerNavigator({
Test: {
screen: createMaterialTopTabNavigator({
Reference: {
screen: CounterContainer
},
Question:{
screen: StaticCounterContainer
}
},{
tabBarPosition: 'bottom',
tabBarOptions:{
activeTintColor:'#d61822',
inactiveTintColor:'#5e5e5e',
pressColor:'#d61822'
}
})
}
},{
drawerPosition: "left",
drawerWidth: Dimensions.get('screen').width*.80,
contentComponent: StaticCounterContainerDrawer
});
let DrawerTabNavigation = createAppContainer(DrawerStack);
class Test extends React.Component {
constructor(props) {
super(props);
console.log(props)
}
render() {
return (
<View style={{flex:1}}>
<View style={{height:50,backgroundColor:'yellow'}}></View>
<Provider store={store}>
<DrawerTabNavigation/>
</Provider>
<View style={{height:50,backgroundColor:'yellow'}}>
<Button
title="Open Drawer"
onPress={() => this.props.navigation.toggleDrawer()}
/>
</View>
</View>
);
}
}
export default Test;
When ever Open Drawer button is pressed
_this3.props.navigation.toggedrawer is not a function this error is showing.
I am providing the screen and the error also:-
Please hekp me to open the drawer on click of a button. Thanks in
advance
this.props.navigation.toggedrawer will work only for the screens which are in DrawerNavigator.
May be try this.
import { DrawerActions } from "react-navigation";
this.props.navigation.dispatch(DrawerActions.toggleDrawer())

How to get previous route in react navigation?

I am user react navigation in react native application. After login I navigate to Home screen from where I want to sign out I should be navigate to previous screen(say Login). But inside navigation props I am unable to find any way to Login screen back without use of goBack function. My navigation is little messy please see my navigation carefuly.
This is my Navigators
import React from 'react';
import{ View, Text } from 'react-native';
// Navigators
import { DrawerNavigator, StackNavigator, TabNavigator } from 'react-navigation'
// Drawer Screens
import Welcome from '../../screens/Welcome';
import Profile from '../../screens/Profile';
// Tab Screens
import Home from '../../screens/Home';
import Message from '../../screens/Message';
//TabNav
const routeConfigs = {
Home: {
screen: Home,
navigationOptions: {
title: 'Home'
}
},
Message: {
screen: Message,
},
}
const tabNavigatorConfig = {
// tabBarComponent: tabBarComponent,
tabBarPosition: 'top',
lazy: true,
tabBarOptions: {
activeTintColor: 'yellow',
inactiveTintColor: 'gray',
style: {
backgroundColor: '#8e24aa',
},
activeBackgroundColor: 'green',
},
header: 'screen'
}
export const TabNav = TabNavigator(routeConfigs, tabNavigatorConfig);
//Used Stack to get Header above TabBar
export const StackNav = StackNavigator({TabNav: { screen: TabNav }});
//DrawerNav
export const DrawerNav = DrawerNavigator (
{
Welcome: { screen: Welcome},
Profile: { screen: Profile },
StackNav: { screen: StackNav}, // Stack Navigator to get Header on each Tabs
},
{
initialRouteName: 'Welcome',
drawerBackgroundColor: '#98eef3',
}
);
This is Welcome or say Login Screen
import React, { Component } from 'react';
import { View, Text, StyleSheet, Button, TouchableOpacity, Modal, BackHandler, Alert, Image } from 'react-native';
import { connect } from 'react-redux';
import firebase from 'firebase';
import {
loginUser
} from '../actions';
import Input from '../components/Input';
import Spinner from '../components/Spinner';
class Welcome extends Component {
constructor(props){
super(props);
this.state = {
modalVisible: false,
email: '',
password: '',
}
this.renderHome = this.renderHome.bind(this);
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton = () => {
Alert.alert(
'Exit App',
'Exiting the application?',
[
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{text: 'OK', onPress: () => BackHandler.exitApp()}
],
{ cancelable: false }
)
return true;
}
static navigationOptions = () => ({
drawerLockMode: 'locked-closed'
})
loginButtonPress() {
this.props.loginUser(this.state.email, this.state.password);
}
renderHome(){
this.props.navigation.navigate('StackNav');
}
renderLoginButton(loading){
if(loading){
return <Spinner />;
}else{
return (
<View style={{alignItems: 'center'}}>
<TouchableOpacity style={styles.button} onPress={this.loginButtonPress.bind(this)} >
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
</View>
);
}
}
render() {
return (
<View style={styles.container}>
{(this.props.user)?this.renderHome():null}
<View style={{flex: 3, justifyContent: 'center'}}>
<Input
placeholder="Email"
keyboardType="email-address"
value={this.state.email}
onChangeText={(email) => this.setState({email})}
/>
<Input
placeholder="Password"
value={this.state.password}
onChangeText={(password) => this.setState({password})}
secureTextEntry
/>
{this.renderLoginButton(this.props.loading)}
);
}
}
mapStateToProp = ({auth}) => {
return {
user: auth.user,
error: auth.error,
loading: auth.loading,
}
}
export default connect(mapStateToProp, { loginUser })(Welcome);
This is Home screen
import React, { Component } from 'react';
import { View, Text, Button, Alert, Animated, BackHandler } from 'react-native';
import { connect } from 'react-redux';
import Header from '../components/Header';
import Ionicons from 'react-native-vector-icons/Ionicons';
export class Home extends Component {
constructor(props){
super(props);
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton = () => {
Alert.alert(
'Exit App',
'Exiting the application?',
[
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{text: 'OK', onPress: () => BackHandler.exitApp()}
],
{ cancelable: false }
)
return true;
}
static navigationOptions = ({navigation}) =>( {
title: 'Home',
header: <Header headerTitle={navigation.state.routeName}/>,
headerTintColor: '#fff',
});
render(){
console.log(this.props.user) // after signout getting undefined
return (
<View
style={{height: 1000}}
>
<View style={{height: 1000}}>
<Text>Home</Text>
</View>
</View>
);
}
}
mapStateToProp = ({auth}) => {
return {
user: auth.user,
}
}
export default connect(mapStateToProp, null)(Home);
Signout is correctly working but need to navigate back to welcome/login screen.
Instead of using goBack you can try Navigation.reset
import { NavigationActions } from "react-navigation";
...
export const logOut = navigation => {
NavigationActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: "Welcome" })]
})
}
use a switch navigator - it is a screen that checks the users current status and forwards them to the appropriate screen.
If user logs in, show user the Home screen
If user logs out show user the Welcome screen
If user arrives unauthenticated show user Welcome screen
update initialRouteName in the in your nav file and added AuthLoadingScreen.
import React from 'react';
import{ View, Text } from 'react-native';
// Navigators
import { DrawerNavigator, StackNavigator, TabNavigator } from 'react-navigation'
// Drawer Screens
import Welcome from '../../screens/Welcome';
import Profile from '../../screens/Profile';
// Tab Screens
import Home from '../../screens/Home';
import Message from '../../screens/Message';
import AuthLoadingScreen from '../../AuthLoading';
//TabNav
const routeConfigs = {
Home: {
screen: Home,
navigationOptions: {
title: 'Home'
}
},
Message: {
screen: Message,
},
}
const tabNavigatorConfig = {
// tabBarComponent: tabBarComponent,
tabBarPosition: 'top',
lazy: true,
tabBarOptions: {
activeTintColor: 'yellow',
inactiveTintColor: 'gray',
style: {
backgroundColor: '#8e24aa',
},
activeBackgroundColor: 'green',
},
header: 'screen'
}
export const TabNav = TabNavigator(routeConfigs, tabNavigatorConfig);
//Used Stack to get Header above TabBar
export const StackNav = StackNavigator({TabNav: { screen: TabNav }});
//DrawerNav
export const DrawerNav = DrawerNavigator (
{
Welcome: { screen: Welcome},
Profile: { screen: Profile },
Authloading: {screen: AuthLoadingScreen}
StackNav: { screen: StackNav}, // Stack Navigator to get Header on each Tabs
},
{
initialRouteName: 'AuthLoading',
drawerBackgroundColor: '#98eef3',
}
);
import React, { Component } from 'react';
import PropTypes from "prop-types";
import {
ActivityIndicator,
AsyncStorage,
StatusBar,
StyleSheet,
View,
Text
} from 'react-native';
import { connect } from 'react-redux'
import { withNavigation } from 'react-navigation'
class AuthLoadingScreen extends Component {
static PropTypes = {
navigation: PropTypes.object,
isAuthenticated: PropTypes.bool
}
componentWillMount() {
this._bootstrapAsync();
}
// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = () => {
const userToken = this.props.isAuthenticated ? 'Tabs' : 'Onboarding';
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away
this.props.navigation.navigate(userToken);
};
// Render any loading content that you like here
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
<Text>hello</Text>
</View>
);
}
}
const mapStateToProps = state => {
return {
isAuthenticated: state.auth || false,
};
};
export default connect(mapStateToProps)(withNavigation(AuthLoadingScreen));

How to access the react-navgiation inside of a functional component or class component which doesnt have access to this.props.navigation?

Im doing this inside the react native platform using expo.
I want to display the list of items ( ListItems.js) All_Employees_screen.js . These items are being rendered via a functional component, I want to have a onRowPress() handler to so that upon clicking it i can navigate it to another view, but I dont know how to do it on react-navigation ?
Or since the new functional component can be a class component( this would be better ) how can i access the navigation thing inside it ?
AllProperties.js
import _ from 'lodash';
import React, {
Component
} from 'react';
import {
Button,
ListView,
ScrollView
} from 'react-native';
import ListItem from './ListItem';
import { connect } from 'react-redux';
import { propertiesFetch } from '../../actions';
// import { FormLabel, FormInput } from 'react-native-elements'
class AllPropertiesScreen extends React.Component {
componentWillMount(){
this.props.propertiesFetch();
this.createDataSource(this.props);
}
// we do this componentWillMount & componentWillReceiveProps (nextProps) thing twice, coz once the component is
// loaded it loads all teh values but when user hits another view like Create property, The Property data still exists
// in the global state object,
// we could move all the dc dataSource code into componentWillReceiveProps but its actually gonna benefit us
// if we make sure that we try to build our data source both when the component first loads up
// & when second time after we go back and forth other compoennts.
componentWillReceiveProps(nextProps){
// nextProps are the next set of props that this component will be rendered with
// this.props is still the old set of props
this.createDataSource(nextProps);
}
createDataSource({ properties }){
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
this.dataSource = ds.cloneWithRows(properties);
}
static navigationOptions = ({ navigation }) => {
const {state, setParams} = navigation;
return {
title: 'All Emplooyee',
headerRight: (
<Button
title='Add'
// onPress={() => setParams({ mode: isInfo ? 'none' : 'info'})}
onPress={() => navigation.navigate('createProperty')
}
/>
),
};
};
goBack(){
console.log('65 - go Back clicked');
}
renderRow(property){
// console.log('67-AllPropertiesScreen =', property);
return <ListItem property={property}
onPress={() => { console.log('65 - go Back clicked') }}
/>;
}
render() {
console.log('72-AllPropertiesScreen this.props', this.props );
return(
<ListView
enableEmptySections
dataSource={this.dataSource}
renderRow={this.renderRow}
/>
);
}
}
const mapStateToProps = state => {
console.log('83 - AllPropertiesScreen state. properties', state );
const properties = _.map(state.properties, (val, uid ) => {
return { ...val, uid }; // { shift: 'Monday'}
});
return { properties };
};
export default connect(mapStateToProps, {propertiesFetch}) (AllPropertiesScreen);
ListItem.js
import React, { Component } from 'react';
import { Text, TouchableWithoutFeedback, View } from 'react-native';
class ListItem extends Component {
// onRowPress(){
// Actions.employeeEdit({ employee: this.props.employee });
// }
render(){
const { agent_name, cell, address } = this.props.property;
console.log('14- ListItem ', this.props);
return (
<View>
<CardSection>
<Text style={styles.titleStyle}>
name
</Text>
<Text style={styles.titleStyle}>
cell
</Text>
<Text style={styles.titleStyle}>
address
</Text>
</CardSection>
</View>
);
}
}
const styles = {
titleStyle: {
fontSize: 18,
paddingLeft: 15
}
}
export default ListItem;
//
main.js ( this is where I have all the navigation paths hookedup.
class App extends React.Component {
render() {
const MainNavigator = TabNavigator({
// auth: { screen : AuthScreen },
// review: { screen: ReviewScreen },
// signup: { screen : SignupScreen },
followup: { screen: FollowupScreen }, welcome: { screen : WelcomeScreen },
auth: { screen : AuthScreen },
signup: { screen : SignupScreen },
main: {
screen: TabNavigator ({
followup: { screen: FollowupScreen },
map: { screen: MapScreen },
deck: { screen: DeckScreen },
settings : {
screen: StackNavigator ({
settings: { screen: SettingsScreen },
// settings: { screen: SettingsScreen },
UserProfile: { screen: UserProfileScreen },
HelpSupport: { screen: HelpSupportScreen },
Notifications: { screen: NotificationsScreen },
Signout: { screen: SignoutScreen } // not working, Navigation object not accessible inside the component
}) //screen: StackNavigator ({
},
followup : {
screen: StackNavigator ({
followup: { screen: FollowupScreen },
allProperties: { screen: AllPropertiesScreen },
createProperty: { screen: PropertyCreateScreen },
Red: { screen: RedPriorityScreen }, // not working, Navigation object not accessible inside the component
GreyPriority: { screen: GreyPriorityScreen },
}) //screen: StackNavigator ({
},
draw: {
screen: DrawerNavigator ({
drawin: { screen: DrawScreen },
}) //screen: StackNavigator ({
}
}) //screen: TabNavigator
}
}, {
navigationOptions: {
tabBarVisible: false
},
lazy: true
});
return (
<Provider store={store}>
<View style={styles.container}>
<MainNavigator />
</View>
</Provider>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
// alignItems: 'center',
justifyContent: 'center',
},
});
Expo.registerRootComponent(App);
Solution suggested by #Matt but as soon as I put the navigation={this.props.navigation} it complains. undefined is not an object ( evaluating this.props.navigation )
renderRow(property){
return (
<ListItem
property={property}
navigation={this.props.navigation}
onPress={() => {
console.log( '70-on Press inside renderRow ');
}}/>
);
}
If the component is not a screen you have to import the navigation.
Try this:
import React from 'react';
import { Button } 'react-native';
import { withNavigation } from 'react-navigation';
class MyBackButton extends React.Component {
render() {
return <Button title="Back" onPress={() => { this.props.navigation.goBack() }} />;
}
}
// withNavigation returns a component that wraps MyBackButton and passes in the
// navigation prop
export default withNavigation(MyBackButton);
For more info check out
https://reactnavigation.org/docs/connecting-navigation-prop.html
This answer was written for old version of react-navigation V1
I had the same exact problem, and I found out that this.props.navigation is injected only in components that are registered as screen in StackNavigator or TabbNavigator.
but in general you can use navigate from NavigationActions class (source here https://v1.reactnavigation.org/docs/navigation-actions.html#navigate)
note: NavigationActions.navigate receives parameters in different way but works the same way.
so this working for me
import { NavigationActions } from 'react-navigation';
let {navigate} = NavigationActions;
renderRow(property) {
return (
<ListItem
property={property}
onPress={() => { navigate({
routeName: 'OtherRoute'
});
}}/>
);
}
<MyComponent navigation={this.props.navigation}/>
Main problem is here. You didn't define your prop navigation in component. You should add this.
Here's how you can use navigation.navigate inside a functional component:
import { Text, TouchableHighlight } from 'react-native';
const MyComponent = ({ navigation }) => (
<TouchableHighlight
onPress={() => navigation.navigate('OtherRoute')}
underlayColor="blue"/>
<Text>Click to Navigate!</Text>
</TouchableHighlight>
);
export default MyComponent;
When you render MyComponent, you will need to pass navigation as a prop. For example, assume HomeContainer is a screen component:
import React from 'react';
import MyComponent from './MyComponent';
export default HomeContainer extends React.Component {
render() {
return (
<MyComponent navigation={this.props.navigation}/>
);
}
}
Change your renderRow method to the following:
renderRow(property) {
return (
<ListItem
property={property}
onPress={() => { this.props.navigation.navigate('OtherRoute'); }}/>
);
}
where 'OtherRoute' is the name of the route you want to navigate to for that row.