Login component react-native - 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>
);
}
}

Related

Login Custom TextInput and Pressable not working after logout

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.

undefined is not an object (evaluating 'Context._context') - React Native

I am trying to wrap one of my navigators with User Context that I created. I have achieved this before in other projects but I am encountering an issue. I Tried following this solution but it doesn't seem to be the same issue I am encountering. I can't exactly tell what is wrong here.
App.js Code :
import React, { useContext, useEffect } from "react";
import { View, Text, AsyncStorage, Button } from "react-native";
import { createStackNavigator } from "#react-navigation/stack";
import HomeScreen from "./src/screens/HomeScreen";
import LoginScreen from "./src/screens/login";
import CalendarScreen from "./src/screens/Calendar";
import SignUpScreen from "./src/screens/signUp";
import { scale, vs } from "react-native-size-matters";
import { createDrawerNavigator } from "#react-navigation/drawer";
import { createMaterialBottomTabNavigator } from "#react-navigation/material-bottom-tabs";
import { Icon } from "react-native-elements";
import UserContext, { UserProvider } from "./src/screens/Context/UserContext";
import { NavigationContainer } from "#react-navigation/native";
const Tab = createMaterialBottomTabNavigator();
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const signedIn = true; //this is for testing
const drawer_style = {
backgroundColor: "#202B35",
activeTintColor: "#000",
width: 200,
};
const drawer_item_style = {
activeTintColor: "orange",
inactiveTintColor: "#fff",
itemStyle: { marginVertical: vs(10) },
};
const non_user_stack = () => {
<Stack.Navigator>
<Stack.Screen
name="Sign in - Cal "
component={LoginScreen}
options={({ navigation }) => ({
headerShown: true,
headerTintColor: "orange",
headerStyle: {
backgroundColor: "#202B35",
},
})}
/>
<Stack.Screen
name="Sign up - Cal "
component={SignUpScreen}
options={({ navigation }) => ({
headerShown: true,
headerTintColor: "orange",
headerStyle: {
backgroundColor: "#202B35",
},
})}
/>
</Stack.Navigator>;
};
const UserMenu = () => {
return (
<NavigationContainer>
<Drawer.Navigator
initialRouteName="Home"
drawerStyle={drawer_style}
drawerContentOptions={drawer_item_style}
drawerType="front"
>
<Drawer.Screen name="Home" component={MyStack} />
</Drawer.Navigator>
</NavigationContainer>
);
};
const MyStack = () => {
return(
<Stack.Navigator>
<Stack.Screen
name="Cal"
component={BottomNav}
options={({ navigation }) => ({
headerShown: true,
headerTintColor: "orange",
headerStyle: {
backgroundColor: "#202B35",
},
headerLeft: (props) => (
<Icon
size={25}
name={"ios-menu"}
iconStyle={{
fontSize: scale(30),
color: "orange",
margin: 5,
marginLeft: 10,
}}
type="ionicon"
color="orange"
onPress={() => {
navigation.toggleDrawer();
}}
/>
),
})}
/>
</Stack.Navigator>
)
};
export default App = () => {
const { isSignedIn, check_and_set_signin_status } = useContext(UserContext); //<-- causes crash
return (
isSignedIn === "false" ? (
<UserProvider>
<UserMenu />
</UserProvider>
) : (
<non_user_stack></non_user_stack>
);
);
};
UserContext.js :
import React, { useState, useEffect } from "react";
import * as Permissions from "expo-permissions";
import axios from "axios";
import { AsyncStorage } from "react-native";
//import registerForPushNotificationsAsync from "../Hooks/registerForPushNotifications";
import Constants from "expo-constants";
const UserContext = React.createContext();
const IS_SIGNEDIN = "is_signed_in";
export const UserProvider = ({ children }) => {
const [isSignedIn, setSignIn] = useState(null);
const [didAuthenticate, setAuthenticated] = useState(null);
//Check if this user already signed in before and didnt log out since their last session
//used for conditional rendering
const check_and_set_signin_status = async () => {
const signed_in = await AsyncStorage.getItem(IS_SIGNEDIN);
if (signed_in == null || signed_in == "false") {
await AsyncStorage.setItem(IS_SIGNEDIN, "false");
setSignIn("false");
} else {
setSignIn("true");
}
};
return (
<UserContext.Provider
value={{
isSignedIn, // well use this for conditional rendering
check_and_set_signin_status,
}}
>
{children}
</UserContext.Provider>
);
};
The Error :
there is some mistake in your code
you are not exporting UserContext but you are importing UserContext
in App.js file
you are trying to use useContext and provider in same file but you
have to useContext inside of Provider child component
you are non_user_stack with first letter capital but you have to
make first letter capital
UserContext.js : you have to export UserContext in this file
import React, { useState, useEffect } from "react";
import { Text } from 'react-native'
import * as Permissions from "expo-permissions";
import axios from "axios";
import { AsyncStorage } from "react-native";
//import registerForPushNotificationsAsync from "../Hooks/registerForPushNotifications";
import Constants from "expo-constants";
const UserContext = React.createContext();
export default UserContext;
const IS_SIGNEDIN = "is_signed_in";
export const UserProvider = ({ children }) => {
const [isSignedIn, setSignIn] = useState(null);
const [didAuthenticate, setAuthenticated] = useState(null);
const check_and_set_signin_status = async () => {
const signed_in = await AsyncStorage.getItem(IS_SIGNEDIN);
if (signed_in == null || signed_in == "false") {
await AsyncStorage.setItem(IS_SIGNEDIN, "false");
setSignIn("false");
} else {
setSignIn("true");
}
};
return (
<UserContext.Provider
value={{
isSignedIn, // well use this for conditional rendering
check_and_set_signin_status,
}}
>
{children}
</UserContext.Provider>
);
};
App.js Code :
const App = () => {
const { isSignedIn, check_and_set_signin_status } = useContext(UserContext); //<-- causes crash
console.log( isSignedIn, check_and_set_signin_status ,"useContext")
return isSignedIn === "false" ? (
<UserMenu />
) : (
<Non_user_stack></Non_user_stack>
);
};
const jsx = () => (
<UserProvider>
<App />
</UserProvider>
);
export default jsx;
In my case I imported badly
import ThemeContext from '../contexts/theme-context';
Instead
import { ThemeContext } from '../contexts/theme-context';
You should always check what you're exporting from your context folder
In my case I import { LocalContext } from ".././services/location/location.context";
instead of import { LocationContext } from ".././services/location/location.context";
Mine was:
I mistakenly imported the file (languageContext.js) instead of its function {LanguageContext} so now it goes like this where I called my context.
import {LanguageContext} from "../../Context/languageContext";
const { language } = useContext(languageContext);
i18n.locale = language;

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.

react native navigation Could not find "store" in either the context or props of "Connect(facebookLogin)

I'm building react native app authentication with facebook login.
I'm using stack navigator and I want to add redux to my app.
I just seperate my files to components and when I use stack navigation with redux I get this error
Could not find "store" in either the context or props of
"Connect(facebookLogin)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(facebookLogin)".
index.android.js
import React, { Component } from 'react';
import { Text, View, StyleSheet, TouchableOpacity, AppRegistry, Image } from 'react-native';
import facebookLogin from './src/components/FacebookLogin';
import Home from './src/components/Home';
import {
StackNavigator,
} from 'react-navigation';
const App = StackNavigator({
Home: { screen: facebookLogin },
HomePage: {screen:Home},
})
AppRegistry.registerComponent('facebookLogin', () => App);
FacebookLogin.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, { Component } from 'react';
import { Text, View, StyleSheet, TouchableOpacity, AppRegistry, Image } from 'react-native';
import FBSDK, { LoginManager, GraphRequest, GraphRequestManager } from 'react-native-fbsdk';
import Icon from 'react-native-vector-icons/FontAwesome';
// redux
import { Provider } from 'react-redux';
import { connect } from 'react-redux';
import { createStore } from 'redux';
import reducers from '../reducers/ProfileReducers';
const store = createStore(reducers, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
class facebookLogin extends Component {
constructor(props) {
super(props);
this.state = {
result: null
}
}
_fbAuth() {
const { navigate } = this.props.navigation;
LoginManager.logInWithReadPermissions(['public_profile','user_birthday']).then((result) => {
if (result.isCancelled) {
console.log('Login was canclled');
}
else {
console.log(result);
const infoRequest = new GraphRequest(
'/me?fields=id,name,picture.width(800).height(800),gender,birthday,first_name,last_name',
null,
(error, result) => {
if (error) {
alert('Error fetching data: ' + error.toString());
} else {
console.log(result);
this.setState({ result });
navigate('HomePage');
}
}
);
// Start the graph request.
new GraphRequestManager().addRequest(infoRequest).start();
}
}, function (error) {
console.log('An error occured:' + error);
})
}
getProfileData() {
const { ImageStyle } = styles;
if (this.state.result) {
return (
<View>
{this.state.result.picture ? <Image style={ImageStyle} source={{ uri: this.state.result.picture.data.url }}></Image> : null}
<Text> first name: {this.state.result.first_name} </Text>
<Text> Last name: {this.state.result.last_name} </Text>
<Text> Gender {this.state.result.gender} </Text>
</View>
)
}
return null;
}
render() {
return (
<Provider store = {store}>
<View style={styles.container}>
<Icon.Button name="facebook" backgroundColor="#3b5998" onPress={() => { this._fbAuth() }}>
<Text style={{fontFamily: 'Arial', fontSize: 15, color:'white'}}>Login with Facebook</Text>
</Icon.Button>
{this.getProfileData()}
</View>
</Provider>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
ImageStyle:{
borderRadius:80,
width:100,
height:100
}
});
const mapStateToProps = (state) => {
return
{ profile: state.profile};
}
export default connect(mapStateToProps)(facebookLogin);
when it was only one component in index.android.js it works fine without any error but when I seperate it to some components using stack navigation I get this error.
my profileReducers
var profile = {
name :'',
email:'',
photo:''
}
const initialState = {
profile,
};
export default (state = initialState, action) => {
console.log("state");
switch (action.type) {
case 'INSERT_PROFILE_DETAILS':
return {
profile: action.payload
}
case 'GET_PROFILE_DETAILS': {
return state;
}
default:
return state;
}
}
Try setting up redux in index.android.js instead so it looks something like this:
// Set up redux store above
const Navigator = StackNavigator({
Home: { screen: facebookLogin },
HomePage: { screen: Home },
});
const App = () => (
<Provider store={store}>
<Navigator />
</Provider>
);
AppRegistry.registerComponent('facebookLogin', () => App);

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 />;
}
}