I have been building an app in React Native and have decided that since my Login
and Signup
components share much of the same code, it would be best to create an AuthState
component and pass login={true}
or login={false}
as props to trigger renderLogin()
or renderSignup()
in AuthState
. However, in doing so, I think I have written extraneous code. I tried to minimize this by writing a renderEmailAndPasswordForms()
function that gets included in renderLogin()
and renderSignup()
but I am sure there's better ways to clean all of this up. Can someone point me in the right direction? Here is my code:
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';
// For Firebase Auth
const auth = firebaseApp.auth();
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
firstName: '',
lastName: '',
email: '',
password: '',
passwordConfirmation: ''
}
}
componentDidMount() {
let user = auth.currentUser;
if (user) {
console.log(msg)
Actions.home
} else {
return;
}
}
render() {
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 email = this.state.email;
let password = this.state.password;
auth.signInWithEmailAndPassword(email, password)
.then(Actions.home)
.catch((error) => {
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() {
}
}
SignUp
andLogin
is a good idea in your case. The occurrence of bothrenderSignup
andrenderLogin
resp._logInUser
andsignUpUser
hint to me thatSignUp
andLogin
are more different than similar. Furthermore, the use of the flaglogin
smells like they should be split up. Therefore, I would move this logic back into the respective components. It might make sense to create a custom input component for the email and password fields, though, and use that. \$\endgroup\$