7
\$\begingroup\$

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() {

  }
}
\$\endgroup\$
3
  • \$\begingroup\$ What version of React are you using? \$\endgroup\$
    – Dan
    Aug 18, 2016 at 6:50
  • \$\begingroup\$ I don't think that combining SignUp and Login is a good idea in your case. The occurrence of both renderSignup and renderLoginresp. _logInUser and signUpUser hint to me that SignUp and Login are more different than similar. Furthermore, the use of the flag login 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\$
    – inyono
    Nov 21, 2016 at 4:13
  • \$\begingroup\$ I'd say this is entirely too much code in a single file. Separate out your login and signup and compare them side by side. If you have duplicated code in them, make a separate component that has the parts you need, then import that in both of them. \$\endgroup\$
    – Eric Blade
    Jan 13, 2017 at 8:51

1 Answer 1

3
\$\begingroup\$

React is component based, so i think you should not combine it, you should split component for the footer, component for the header, component for the container and if you want to render inside the container you can use

Page.jsx

...
render() {
    return (
      <MainContainer>
          <Header/>
          {React.Children.only(this.props.children)}
          <Footer/>
      </MainContainer>
    );
  }
...

then you can use it like this

Login.jsx

import React, { Component } from 'react';
import LoginForm from '../LoginForm.jsx';
import Page from '../Page.jsx';

class Login extends Component {
  render() {
    return (
      <Page children={LoginForm}/>
    );
  }
}

export default Login;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.