Login Custom TextInput and Pressable not working after logout - react-native

This is my Navigation
import React from 'react'
import { NavigationContainer } from '#react-navigation/native'
import { createNativeStackNavigator } from '#react-navigation/native-stack'
import { Login } from '../views/Login'
import { Home } from '../views/modules/Home'
const Stack = createNativeStackNavigator();
const Navigation = () => {
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Home" component={Home} />
</Stack.Navigator>
</NavigationContainer>
)
}
export { Navigation }
This is my Login
import React, { useState, useRef, } from 'react'
import { View, StyleSheet, Alert } from 'react-native'
import FormData from 'form-data'
import { CustomInput } from '../components/CustomInput'
import { CustomButton } from '../components/CustomButton'
import { CustomModalAlert } from '../components/CustomModalAlert'
import { useNavigation } from '#react-navigation/native'
const Login = () => {
const navigation = useNavigation()
const [showModal, setShowModal] = useState(false)
const [code, setCode] = useState("")
const setModalData = (data) => {
setShowModal(data.bool)
if (data.bool) {
navigation.navigate('Home')
}
}
const submitLoginForm = () => {
var data = new FormData();
data.append("code", code);
fetch("http://192.168.3.200/mobile_login/api", {
method : 'POST',
headers : {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
},
body : data,
})
.then((res)=>res.json())
.then((res)=>{
if (res.success == 1) {
setShowModal(true)
} else {
Alert.alert(
"Opps!",
res.message,
[{ text: "OK" }]
)
}
})
.catch((err) => {
Alert.alert(
"Network Error!",
"Please check your internet connection",
[{ text: "OK" }]
)
})
}
return (
<View style={styles.container}>
<CustomInput
placeholder='Code'
autoFocus={true}
value={code}
onChangeText={(code) => setCode(code)}
/>
<CustomButton
text={'LOG IN'}
onPress={() => submitLoginForm()}
/>
<CustomModalAlert
setData={setModalData}
showModal={showModal}
title={'Confirmation'}
text={'Go to Home?'}
cancelButtonLabel={'Cancel'}
confirmButtonLabel={'Confirm'}
/>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
})
export { Login }
This is Home
import React, { useState } from 'react'
import { View, Text, StyleSheet } from 'react-native'
import Icon from 'react-native-vector-icons/MaterialIcons'
import { useNavigation } from '#react-navigation/native'
import { CustomModalAlert } from '../../components/CustomModalAlert'
import { CustomFloatingLogout } from '../../components/CustomFloatingLogout'
const Home = () => {
const [showModal, setShowModal] = useState(false)
const navigation = useNavigation()
const logout = () => {
setShowModal(true)
}
const setModalData = (data) => {
setShowModal(data.bool)
if (data.bool) {
navigation.navigate('Login')
}
}
return (
<View style={styles.container}>
<Text><Icon name="person" size={30} /></Text>
<Text>Home</Text>
<CustomFloatingLogout onPress={() => logout()} />
<CustomModalAlert
setData={setModalData}
showModal={showModal}
title={'Logout?'}
text={'Go to Home?'}
cancelButtonLabel={'Cancel'}
confirmButtonLabel={'Yes, Log Out!'}
/>
</View>
)
}
const styles = StyleSheet.create({ container: { flex: 1, }, })
export { Home }
Login View
Home View
When I click the login button in Login View then Ok the popup modal, it goes to the Home View and the homes floating button is working then when I click the Home View floating button to logout it goes to Login View but the TextInput and Button is not working
The question is how can I make TextInput and Button work?
Sorry, I'm new in react-native. Thanks for help.

I have solved and will answer my question 😅 thanks to #Kailash
const setModalData = (data) => {
setShowModal(data.bool)
if (data.bool) {
setShowModal(false)
props.navigation.navigate('Home')
}
}
I just added
setShowModal(false)
under
if (data.bool) {
in Login
The problem is I forgot to close the modal before navigating.

Looks like you have opened Modal but you haven't closed. So its causing this issue.
Reason: If you have used transparent modal and then click on navigate to other screen, in this case if the Modal is still opened, then you will see the new screen but you won't be able to click it, because of transparent modal.
In your case you should be setting your showModal state to false, once click on the label 'Yes, Log Out!'. And do the same for your Login Module as well, if not closed.

Related

Navigation issue in Reat Naivgation, React Native

I am using react-navigation 5 in my mobile app and I am stuck in implementing a log-off feature.
The scenario is I have a stack navigator and a bottom tab navigator in my app. The app starts with the stack navigator (Login feature and Reset Password Feature) and on login goes to the dashboard Page which is from the bottom tab navigator. Now on the Dashboard page, I am implementing a logout feature which when clicked should take me to the login page (part of stack navigator), and no matter what I try it keeps giving me errors like these
The action 'RESET' with payload {"index":0,"routes":[{"name":"AuthNavigator"}]} was not handled by any navigator.
Here are my code snippets right from start
Component Called from App.js
import React, { useState, useEffect, useContext } from "react";
import { ActivityIndicator } from "react-native";
import AsyncStorage from '#react-native-async-storage/async-storage';
import { Center } from "../../components/Center";
import { AuthContext } from "../authentication/AuthProvider";
import { NavigationContainer } from "#react-navigation/native";
import { AuthNavigator } from "./AuthNavigator";
import { MainTabNavigator } from "./MainTabNavigator";
export default function App() {
const { user, login } = useContext(AuthContext);
const [loading, setLoading] = useState(true);
useEffect(() => {
// check if the user is logged in or not
//AsyncStorage.removeItem("user") //- uncomment this and refresh emulator to start from login screen
AsyncStorage.getItem("user")
.then(userString => {
if (userString) {
login();
}
setLoading(false);
})
.catch(err => {
console.log(err);
});
}, []);
if (loading) {
return (
<Center>
<ActivityIndicator size="large" />
</Center>
);
}
return (
<NavigationContainer>
{user ? <MainTabNavigator /> : <AuthNavigator />}
</NavigationContainer>
);
}
AuthNavigator.js
import React from "react";
import { createStackNavigator } from '#react-navigation/stack';
import Login from '../authentication/Login';
import ResetPassword from '../authentication/ResetPassword';
import { MainTabNavigator } from "./MainTabNavigator";
const Stack = createStackNavigator();
export const AuthNavigator = () => {
return (
<Stack.Navigator initialRouteName="Login">
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="ResetPassword" options={{headerTitle: "Reset Password"}} component={ResetPassword} />
</Stack.Navigator>
);
}
MainTabNavigator.js
import * as React from 'react';
import { Text, View, Image, StyleSheet, Platform } from 'react-native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import DashboardView from '../dashboard/DashboardView';
import Search from '../searchLoan/Search';
import { colors } from '../../styles';
const iconHome = require('../../../assets/images/tabbar/home.png');
const iconGrids = require('../../../assets/images/tabbar/grids.png');
const searchIcon = require('../../../assets/images/pages/search_24px.png');
const Tab = createBottomTabNavigator();
const tabData = [
{
name: 'Dashboard',
component: DashboardView,
icon: iconHome,
},
{
name: 'Search',
component: Search,
icon: searchIcon,
},
];
export const MainTabNavigator = () => {
return (
<Tab.Navigator tabBarOptions={{ style: { height: Platform.OS === 'ios' ? 90 : 50 } }}>
{tabData.map((item, idx) => (
<Tab.Screen
key={`tab_item${idx + 1}`}
name={item.name}
component={item.component}
options={{
tabBarIcon: ({ focused }) => (
<View style={styles.tabBarItemContainer}>
<Image
resizeMode="contain"
source={item.icon}
style={[styles.tabBarIcon, focused && styles.tabBarIconFocused]}
/>
</View>
),
tabBarLabel: ({ focused }) => <Text style={{ fontSize: 12, color: focused ? colors.primary : colors.gray }}>{item.name}</Text>,
title: item.name,
}}
/>
))}
</Tab.Navigator>
);
};
const styles = StyleSheet.create({
tabBarItemContainer: {
alignItems: 'center',
justifyContent: 'center',
borderBottomWidth: 2,
borderBottomColor: colors.white,
paddingHorizontal: 10,
bottom: Platform.OS === 'ios' ? -5 : 0,
},
tabBarIcon: {
width: 23,
height: 23,
},
tabBarIconFocused: {
tintColor: colors.primary,
},
});
DashboardView.js
import React , {useContext }from 'react';
import { StyleSheet, View, TouchableOpacity, Text } from 'react-native';
import {Header} from 'react-native-elements';
import AntIcon from "react-native-vector-icons/AntDesign";
import { colors, fonts } from '../../styles';
import AmountDetails from './AmountDetails';
import DashboardFields from './DashboardFields';
import { AuthContext } from "../authentication/AuthProvider";
import { CommonActions } from "#react-navigation/native";
export default function DashboardView(props) {
const appLogOut = () => {
const { logout } = useContext(AuthContext);
console.log('props', props)
if(logout){
// console.log("Navigation Object", navigation)
props.navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{ name: "AuthNavigator" }],
}));
}
}
return (
<View style={styles.container}>
<Header containerStyle = {{backgroundColor: colors.primary}}
centerComponent={{ text: 'Dashboard', style: { color: colors.white, backgroundColor: colors.primary } }}
rightComponent = <TouchableOpacity onPress={appLogOut()}><AntIcon name="logout" color="white" size={25}/></TouchableOpacity>
/>
<View style={styles.container}>
<View>
<AmountDetails />
</View>
<View style={styles.dashboardFields}>
<DashboardFields />
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.gray,
},
dashboardFields: {
marginTop: 20,
},
});
You should try calling the login screen directly, not the whole stack.
CommonActions.reset({
index: 0,
routes: [{ name: "Login" }],
}));
As the other answer said, you have incorrect route name (AuthNavigator).
However, you're conditionally defining screens based on if the user is logged in. You don't need to do anything extra when logging out. Conditionally defining screens means React Navigation can automatically handle which screen to show when the conditional changes.
So you need to remove the code which does reset.
From the docs:
It's important to note that when using such a setup, you don't need to manually navigate to the Home screen by calling navigation.navigate('Home') or any other method. React Navigation will automatically navigate to the correct screen when isSigned in changes - Home screen when isSignedIn becomes true, and to SignIn screen when isSignedIn becomes false. You'll get an error if you attempt to navigate manually.
More details: https://reactnavigation.org/docs/auth-flow/

Login component react-native

I am making a react-native application.
I am trying to find out how can I show or hide the login component on the basis of a token stored. If the token is present in the storage, it would skip the login screen to the dashboard.
Else it will show login screen.
Here is the code to the app.
import React, { useState } from 'react';
import { StyleSheet, Text, View, Button, AsyncStorage } from 'react-native';
import Login from './components/Login';
import Dashboard from './components/Dashboard';
export default function App() {
var [ token, setToken ] = useState('');
function loginHandler(recievedToken) {
setToken(recievedToken);
}
async function _readData() {
try {
const value = await AsyncStorage.getItem('Token');
console.log(value);
if (value !== null) {
// We have data!!
loginHandler(value)
} else {
loginHandler(null);
}
} catch (error) {
// Error retrieving data
}
};
return (
<View>
<Login getToken={_readData()} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
You can put conditional statement in your code.
Try this code out.
import React, { useState } from 'react';
import { StyleSheet, Text, View, Button, AsyncStorage, ActivityIndictor } from 'react-native';
import Login from './components/Login';
import Dashboard from './components/Dashboard';
export default function App() {
var [ token, setToken ] = useState('');
var [ loading, setLoading ] = useState(true);
function loginHandler(recievedToken) {
setToken(recievedToken);
setLoading(false);
}
async function _readData() {
try {
const value = await AsyncStorage.getItem('Token');
console.log(value);
if (value !== null) {
// We have data!!
loginHandler(value)
} else {
loginHandler(null);
}
} catch (error) {
// Error retrieving data
}
};
if( loading ) {
<ActivityIndictor/>
}
if(token == null){
return (
<View>
<Login getToken={_readData()} />
</View>
);
} else {
return (
<View>
<Dashboard />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Let me know if some error or correction.
Here AuthStack is Login Screen and BottomNavigation is DashBoard.
import React, { useEffect, useState } from "react";
import { NavigationContainer } from "#react-navigation/native";
import AuthStackScreen from "./routes/AuthStack";
import BottomNavigation from "./routes/BottomNavigator";
import firebase from "./config/firebase";
export default App = () => {
const [isLogin, setIsLogin] = useState(false);
const checkLoginIn = () => {
firebase.auth().onAuthStateChanged(user => {
if (user) {
setIsLogin(true);
} else {
setIsLogin(false);
}
});
};
useEffect(() => {
checkLoginIn();
}, []);
return (
<NavigationContainer>
{isLogin ? <BottomNavigation /> : <AuthStackScreen />}
</NavigationContainer>
);
};
In my case
I just used initialRouteName
import React, {Component} from 'react';
import {NavigationContainer} from '#react-navigation/native';
import {createNativeStackNavigator} from '#react-navigation/native-stack';
import AsyncStorage from '#react-native-async-storage/async-storage';
import Home from './components/Home';
import Login from './components/Login';
const Stack = createNativeStackNavigator();
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
routeName: 'Login',
};
}
async componentDidMount() {
const token = JSON.parse(await AsyncStorage.getItem('token'));
if (token !== null) {
this.setState({
routeName: 'Bluetooth',
});
}
SplashScreen.hide();
}
render() {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName={this.state.routeName}
screenOptions={{
headerShown: false,
}}>
<>
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Home" component={Home} />
</>
</Stack.Navigator>
</NavigationContainer>
);
}
}

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

React Native Redux conditional LoggedIn render causes race condition

So I am pretty new to React Native and completely new to redux. I have created an auth flow using a conditional React Navigation render that works apart from giving an error, I believe is causedby a race condition. What happens that it checks if a user is signed in and renders based on if they are or not. But if the user is already logged in, it starts to render the LoginScreen, detects they are logged in, then tries to re-render, causing the following error:
"Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the Icon component."
My main component looks like this:
import React, { Component } from "react";
import { StyleSheet, Text, View, AsyncStorage } from "react-native";
import { connect, Provider } from "react-redux";
import Reactotron from "reactotron-react-native";
import { logIn } from "../actions";
import { SignedIn, SignedOut } from "../components/Nav";
import { isSignedIn } from "../components/Auth";
import LoginScreen from "../containers/LoginScreen";
class RootApp extends Component {
async checkSignedIn() {
res = await isSignedIn();
if (res != false) {
expires = String(res.expires);
this.props.logIn(res.fbToken, expires);
} else {
console.log("Not logged in");
}
}
async componentWillMount() {
await this.checkSignedIn();
}
render() {
if (this.props.auth.signedIn == true) {
return <SignedIn />;
} else {
return <SignedOut />;
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
fontSize: 96
}
});
const mapStateToProps = state => {
return {
auth: state.auth
};
};
const mapDispatchToProps = dispatch => {
return {
logIn: fbToken => {
dispatch(logIn(fbToken, expires));
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(RootApp);
The Nav looks like
import React, { Component } from "react";
import { TabNavigator, StackNavigator } from "react-navigation";
import Tasks from "../screens/Tasks";
import Home from "../screens/Home";
import Message from "../screens/Message";
import Profile from "../screens/Profile";
//import WelcomeScreen from "../screens/WelcomeScreen";
import PhoneContacts from "../screens/PhoneContacts";
import { SimpleLineIcons } from "#expo/vector-icons";
import LoginScreen from "../containers/LoginScreen";
const InviteNavigator = StackNavigator({
DeathMessage: { screen: Message },
PhoneContacts: { screen: PhoneContacts }
});
export const SignedIn = TabNavigator({
Tasks: {
screen: Tasks,
navigationOptions: {
tabBarIcon: ({ tintColor }) =>
<SimpleLineIcons name="list" size={30} />
}
},
Home: {
screen: Home,
navigationOptions: {
tabBarIcon: ({ tintColor }) =>
<SimpleLineIcons name="home" size={30} />
}
},
Message: {
screen: InviteNavigator,
navigationOptions: {
tabBarIcon: ({ tintColor }) =>
<SimpleLineIcons name="envelope-letter" size={30} />
}
},
Profile: {
screen: Profile,
navigationOptions: {
tabBarIcon: ({ tintColor }) =>
<SimpleLineIcons name="user" size={30} />
}
}
});
export const SignedOut = StackNavigator({
SignIn: {
screen: LoginScreen,
navigationOptions: {
title: "Sign In"
}
}
});
LoginScreen looks like:
import { connect } from "react-redux";
import React, { Component } from "react";
import {
Button,
View,
Text,
ActivityIndicator,
Alert,
FlatList
} from "react-native";
import { NavigationActions } from "react-navigation";
import { SocialIcon, Card } from "react-native-elements";
import Reactotron from "reactotron-react-native";
import { AsyncStorage } from "react-native";
import { logIn } from "../actions";
import { signIn } from "../components/Auth";
class SignIn extends Component {
async handleClick() {
res = await signIn();
if (res.type == "success") {
expires = String(res.expires);
AsyncStorage.setItem("fbToken", res.token);
AsyncStorage.setItem("expires", expires);
this.props.logIn(res.token, expires);
} else {
console.log("Login Failed");
}
}
render() {
return (
<View style={{ paddingVertical: 20 }}>
<Card title="finis Requires A Facebook Account To Operate">
<SocialIcon
title="Fred"
button
type="facebook"
onPress={() => this.handleClick()}
/>
</Card>
</View>
);
}
}
const mapDispatchToProps = dispatch => {
return {
logIn: fbToken => {
dispatch(logIn(fbToken, expires));
}
};
};
LoginScreen = connect(null, mapDispatchToProps)(SignIn);
export default LoginScreen;
Any help would be greatly appreciated. Happy to completely redesign if pointed in the right direction.
Sorted by adding an auth.checking prop and rendering an activity spinner until it has checked.
render() {
if (this.props.auth.checking == true) {
return (
<ActivityIndicator
animating={true}
style={styles.activityIndicator}
size="large"
/>
);
} else if (this.props.auth.signedIn == true) {
return <SignedIn />;
} else {
return <SignedOut />;
}
}