In the code below (in auth_shared.js), I have a Loading
ponent that I wish to display when the promises signInWithEmailAndPassword()
or createUserWithEmailAndPassword()
are called (whenever the user hits the "Log in" or "Sign up" buttons).
To do this, I thought it was best to create a state called isLoading
and set it to false
initially. In render()
, I then check the value of isLoading
and determine if I should load the Loading
ponent or the Log in or Sign up fields. If signInWithEmailAndPassword()
is called I then set isLoading = true
in an attempt to display the Loading
ponent while the promise is validating the users email
and password
. However, this does not seem to work and I am not sure why! Can someone please provide some insight into this? Thank you. Here is my code:
loading.js
import React, { Component } from 'react';
import {
ActivityIndicator,
Text,
View
} from 'react-native';
import styles from 'TextbookSwap/app_styles';
export default class Loading extends Component {
render() {
return (
<View style={styles.loadingBG}>
<ActivityIndicator
animating={true}
color="white"
size="large"
style={{margin: 15}}
/>
<Text style={styles.loadingText}>
{this.props.loadingText}
</Text>
</View>
);
}
}
login.js
import React, { Component } from 'react';
// Components
import AuthShared from '../auth_shared';
export default class Login extends Component {
render() {
return (
<AuthShared login={true}/>
);
}
}
signup.js
import React, { Component } from 'react';
// Components
import AuthShared from '../auth_shared';
export default class SignUp extends Component {
render() {
return (
<AuthShared login={false}/>
);
}
}
auth_shared.js
import React, { Component } from 'react';
import {
AlertIOS,
Dimensions,
Image,
ScrollView,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View
} from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import { Actions } from 'react-native-router-flux';
import firebaseApp from 'TextbookSwap/firebase_setup';
import styles from 'TextbookSwap/app_styles';
// Components
import HeaderImage from './header_image';
import Loading from './loading.js';
// For Firebase Auth
const auth = firebaseApp.auth();
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
firstName: '',
lastName: '',
email: '',
password: '',
passwordConfirmation: ''
}
}
ponentDidMount() {
let user = auth.currentUser;
if (user) {
console.log(msg)
Actions.home
} else {
return;
}
}
render() {
if (this.state.isLoading) {
return <Loading loadingText="Loading..." />
} else {
return (
<View style={styles.mainContainer}>
<KeyboardAwareScrollView
style={styles.scrollView}
keyboardShouldPersistTaps={false}
automaticallyAdjustContentInsets={true}
alwaysBonceVertical={false}
>
<View style={styles.formInputContainer}>
<HeaderImage />
{this.props.login ? this.renderLogin() : this.renderSignup()}
</View>
{this.props.login ? this.renderFooter() : null}
</KeyboardAwareScrollView>
</View>
);
}
}
renderLogin() {
return (
<View>
{this.renderEmailAndPasswordForms()}
<View style={styles.authButtonContainer}>
<TouchableOpacity
style={styles.authButton}
onPress={this._logInUser.bind(this)}
>
<Text style={styles.actionText}>Log me in!</Text>
</TouchableOpacity>
</View>
</View>
);
}
renderSignup() {
return (
<View>
<View style={[styles.formInputWrapper, styles.formInputInlineWrapper]}>
<View style={{borderColor: '#50514F', borderLeftWidth: 0, borderRightWidth: 0.5, borderTopWidth: 0, borderBottomWidth: 0}}>
<TextInput
style={[styles.formInput, styles.formInputInline]}
autoFocus={true}
autoCapitalize="none"
autoCorrect={false}
placeholder="First Name"
onChangeText={(firstName) => this.setState({firstName})}
/>
</View>
<TextInput
style={[styles.formInput, styles.formInputInline]}
autoFocus={true}
autoCapitalize="none"
autoCorrect={false}
placeholder="Last Name"
onChangeText={(lastName) => this.setState({lastName})}
/>
</View>
{this.renderEmailAndPasswordForms()}
<View style={styles.formInputWrapper}>
<TextInput
style={styles.formInput}
secureTextEntry={true}
autoCapitalize="none"
autoCorrect={false}
placeholder="Password Confirmation"
onChangeText={(passwordConfirmation) => this.setState({passwordConfirmation})}
/>
</View>
<View style={styles.authButtonContainer}>
<TouchableOpacity
style={styles.authButton}
onPress={this._signUpUser.bind(this)}
>
<Text style={styles.actionText}>Sign me up!</Text>
</TouchableOpacity>
</View>
</View>
);
}
renderEmailAndPasswordForms() {
return (
<View>
<View style={styles.formInputWrapper}>
<TextInput
style={styles.formInput}
autoFocus={true}
autoCapitalize="none"
autoCorrect={false}
placeholder="Email"
onChangeText={(email) => this.setState({email})}
/>
</View>
<View style={styles.formInputWrapper}>
<TextInput
style={styles.formInput}
secureTextEntry={true}
autoCapitalize="none"
autoCorrect={false}
placeholder="Password"
onChangeText={(password) => this.setState({password})}
/>
</View>
</View>
);
}
renderFooter() {
return (
<View style={styles.footer}>
<TouchableOpacity
style={styles.footerButton}
onPress={Actions.signup}
>
<Text style={styles.actionText}>No account? Create one!</Text>
</TouchableOpacity>
</View>
);
}
_logInUser() {
let { isLoading, email, password } = this.state;
auth.signInWithEmailAndPassword(email, password)
.then(() => {
isLoading = true;
Actions.home;
isLoading = false;
})
.catch((error) => {
isLoading = false;
switch(error.code) {
case "auth/wrong-password":
AlertIOS.alert('Uh oh!', 'Invalid password! Please try again.');
break;
case "auth/invalid-email":
AlertIOS.alert('Uh oh!', 'Invalid email! Please try again.');
break;
case "auth/user-not-found":
AlertIOS.alert('Uh oh!', 'Please check your credentials and try again');
break;
}
});
}
_signUpUser() {
let { firstName, lastName, email, password, passwordConfirmation } = this.state;
// Check that email, password, and passwordConfirmation are present
if (!firstName || !lastName || !email || !password || !passwordConfirmation) {
AlertIOS.alert('Uh oh!', 'Please fill out all fields');
} else if (password == passwordConfirmation) {
auth.createUserWithEmailAndPassword(email, password)
.then((user) => {
user.updateProfile({
displayName: `${firstName} ${lastName}`
})
.then(Actions.home)
.catch((error) => {
AlertIOS.alert(`${error.code}`, `${error.message}`);
});
})
.catch((error) => {
AlertIOS.alert(`${error.code}`, `${error.message}`);
});
} else {
AlertIOS.alert('Uh oh!', 'Passwords do not match');
}
}
}
In the code below (in auth_shared.js), I have a Loading
ponent that I wish to display when the promises signInWithEmailAndPassword()
or createUserWithEmailAndPassword()
are called (whenever the user hits the "Log in" or "Sign up" buttons).
To do this, I thought it was best to create a state called isLoading
and set it to false
initially. In render()
, I then check the value of isLoading
and determine if I should load the Loading
ponent or the Log in or Sign up fields. If signInWithEmailAndPassword()
is called I then set isLoading = true
in an attempt to display the Loading
ponent while the promise is validating the users email
and password
. However, this does not seem to work and I am not sure why! Can someone please provide some insight into this? Thank you. Here is my code:
loading.js
import React, { Component } from 'react';
import {
ActivityIndicator,
Text,
View
} from 'react-native';
import styles from 'TextbookSwap/app_styles';
export default class Loading extends Component {
render() {
return (
<View style={styles.loadingBG}>
<ActivityIndicator
animating={true}
color="white"
size="large"
style={{margin: 15}}
/>
<Text style={styles.loadingText}>
{this.props.loadingText}
</Text>
</View>
);
}
}
login.js
import React, { Component } from 'react';
// Components
import AuthShared from '../auth_shared';
export default class Login extends Component {
render() {
return (
<AuthShared login={true}/>
);
}
}
signup.js
import React, { Component } from 'react';
// Components
import AuthShared from '../auth_shared';
export default class SignUp extends Component {
render() {
return (
<AuthShared login={false}/>
);
}
}
auth_shared.js
import React, { Component } from 'react';
import {
AlertIOS,
Dimensions,
Image,
ScrollView,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View
} from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import { Actions } from 'react-native-router-flux';
import firebaseApp from 'TextbookSwap/firebase_setup';
import styles from 'TextbookSwap/app_styles';
// Components
import HeaderImage from './header_image';
import Loading from './loading.js';
// For Firebase Auth
const auth = firebaseApp.auth();
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
firstName: '',
lastName: '',
email: '',
password: '',
passwordConfirmation: ''
}
}
ponentDidMount() {
let user = auth.currentUser;
if (user) {
console.log(msg)
Actions.home
} else {
return;
}
}
render() {
if (this.state.isLoading) {
return <Loading loadingText="Loading..." />
} else {
return (
<View style={styles.mainContainer}>
<KeyboardAwareScrollView
style={styles.scrollView}
keyboardShouldPersistTaps={false}
automaticallyAdjustContentInsets={true}
alwaysBonceVertical={false}
>
<View style={styles.formInputContainer}>
<HeaderImage />
{this.props.login ? this.renderLogin() : this.renderSignup()}
</View>
{this.props.login ? this.renderFooter() : null}
</KeyboardAwareScrollView>
</View>
);
}
}
renderLogin() {
return (
<View>
{this.renderEmailAndPasswordForms()}
<View style={styles.authButtonContainer}>
<TouchableOpacity
style={styles.authButton}
onPress={this._logInUser.bind(this)}
>
<Text style={styles.actionText}>Log me in!</Text>
</TouchableOpacity>
</View>
</View>
);
}
renderSignup() {
return (
<View>
<View style={[styles.formInputWrapper, styles.formInputInlineWrapper]}>
<View style={{borderColor: '#50514F', borderLeftWidth: 0, borderRightWidth: 0.5, borderTopWidth: 0, borderBottomWidth: 0}}>
<TextInput
style={[styles.formInput, styles.formInputInline]}
autoFocus={true}
autoCapitalize="none"
autoCorrect={false}
placeholder="First Name"
onChangeText={(firstName) => this.setState({firstName})}
/>
</View>
<TextInput
style={[styles.formInput, styles.formInputInline]}
autoFocus={true}
autoCapitalize="none"
autoCorrect={false}
placeholder="Last Name"
onChangeText={(lastName) => this.setState({lastName})}
/>
</View>
{this.renderEmailAndPasswordForms()}
<View style={styles.formInputWrapper}>
<TextInput
style={styles.formInput}
secureTextEntry={true}
autoCapitalize="none"
autoCorrect={false}
placeholder="Password Confirmation"
onChangeText={(passwordConfirmation) => this.setState({passwordConfirmation})}
/>
</View>
<View style={styles.authButtonContainer}>
<TouchableOpacity
style={styles.authButton}
onPress={this._signUpUser.bind(this)}
>
<Text style={styles.actionText}>Sign me up!</Text>
</TouchableOpacity>
</View>
</View>
);
}
renderEmailAndPasswordForms() {
return (
<View>
<View style={styles.formInputWrapper}>
<TextInput
style={styles.formInput}
autoFocus={true}
autoCapitalize="none"
autoCorrect={false}
placeholder="Email"
onChangeText={(email) => this.setState({email})}
/>
</View>
<View style={styles.formInputWrapper}>
<TextInput
style={styles.formInput}
secureTextEntry={true}
autoCapitalize="none"
autoCorrect={false}
placeholder="Password"
onChangeText={(password) => this.setState({password})}
/>
</View>
</View>
);
}
renderFooter() {
return (
<View style={styles.footer}>
<TouchableOpacity
style={styles.footerButton}
onPress={Actions.signup}
>
<Text style={styles.actionText}>No account? Create one!</Text>
</TouchableOpacity>
</View>
);
}
_logInUser() {
let { isLoading, email, password } = this.state;
auth.signInWithEmailAndPassword(email, password)
.then(() => {
isLoading = true;
Actions.home;
isLoading = false;
})
.catch((error) => {
isLoading = false;
switch(error.code) {
case "auth/wrong-password":
AlertIOS.alert('Uh oh!', 'Invalid password! Please try again.');
break;
case "auth/invalid-email":
AlertIOS.alert('Uh oh!', 'Invalid email! Please try again.');
break;
case "auth/user-not-found":
AlertIOS.alert('Uh oh!', 'Please check your credentials and try again');
break;
}
});
}
_signUpUser() {
let { firstName, lastName, email, password, passwordConfirmation } = this.state;
// Check that email, password, and passwordConfirmation are present
if (!firstName || !lastName || !email || !password || !passwordConfirmation) {
AlertIOS.alert('Uh oh!', 'Please fill out all fields');
} else if (password == passwordConfirmation) {
auth.createUserWithEmailAndPassword(email, password)
.then((user) => {
user.updateProfile({
displayName: `${firstName} ${lastName}`
})
.then(Actions.home)
.catch((error) => {
AlertIOS.alert(`${error.code}`, `${error.message}`);
});
})
.catch((error) => {
AlertIOS.alert(`${error.code}`, `${error.message}`);
});
} else {
AlertIOS.alert('Uh oh!', 'Passwords do not match');
}
}
}
Share
Improve this question
edited Aug 5, 2016 at 3:47
szier
asked Aug 5, 2016 at 3:19
szierszier
1,5073 gold badges19 silver badges32 bronze badges
0
1 Answer
Reset to default 4In your constructor you should set isLoading
to false
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true, // change this to false
Whenever you want to show the loading indicator, you should change isLoading
to true
before the async call, not on the callback.
You should only change the state via setState
(see https://facebook.github.io/react/docs/ponent-api.html)
_logInUser() {
let { isLoading, email, password } = this.state;
this.setState({isLoading:true}); // move state change here
auth.signInWithEmailAndPassword(email, password)
.then(() => {
Actions.home;
this.setState({isLoading:false}); // use setState
})
.catch((error) => {
this.setState({isLoading:false}); // use setState
switch(error.code) {
case "auth/wrong-password":
AlertIOS.alert('Uh oh!', 'Invalid password! Please try again.');
break;
case "auth/invalid-email":
AlertIOS.alert('Uh oh!', 'Invalid email! Please try again.');
break;
case "auth/user-not-found":
AlertIOS.alert('Uh oh!', 'Please check your credentials and try again');
break;
}
});
}