This tutorial shows you how to create the building blocks of a login screen such as input forms. We'll also set a variable to check whether the user has logged in, and only show sensitive information once they have.
We'll assume you know how to make custom components and hooks in React Native. We'll also assume you already have a multi-screen app whose initial screen is WelcomeScreen.js.
Note: this draft presents only a rudimentary synopsis of this tutorial. Please watch the video for details.
Let's say you have a simple WelcomeScreen.js with a simple button users can click to proceed, but you want them to log in first to ensure user privacy or accountability. We're going to create a <LoginForm> component to stand in its place until the user has logged in.
We'll build our login form from a series of nested components, including input fields and a submit button. We'll make these as generic as possible so we can re-use them for other screens or apps.
This will be just a re-usable button that looks a little better than the one that comes by default with React Native.
import { Text, TouchableOpacity } from "react-native";
<TouchableOpacity onPress={ props.whenPressed }>
</TouchableOpacity>
<TouchableOpacity onPress={ props.whenPressed }>
<Text>{ props.children }</Text>
</TouchableOpacity>
import React from "react";
import { Text, TouchableOpacity } from "react-native";
const SubmitButton = props => {
return (
<TouchableOpacity onPress={ props.whenPressed } style={ styles.button }>
<Text style={ styles.buttonText }>{ props.children }</Text>
</TouchableOpacity>
);
};
export default SubmitButton;
const styles = {
button: {
height: 40,
marginVertical: 5,
borderColor: "teal",
borderWidth: 2,
borderRadius: 8,
paddingVertical: 4,
paddingHorizontal: 10
},
buttonText: {
alignSelf: "center",
color: "teal",
fontSize: 20,
fontWeight: "bold"
}
};
Next we'll make a simple <Input> component with a label and input field.
import { View, Text, TextInput } from "react-native";
const Input = () => (
<View>
<View>
<Text>Label</Text>
</View>
<View>
<TextInput/>
</View>
</View>
);
<Text style={ styles.label }>{ props.label }</Text>
import React from "react";
import { View, Text, TextInput } from "react-native";
const Input = props => (
<View>
<View>
<Text>{props.label}</Text>
</View>
<View>
<TextInput
autoCorrect={false}
secureTextEntry={props.secureTextEntry}
placeholder={props.placeholder}
value={props.value}
onChangeText={props.onChangeText}
/>
</View>
</View>
);
export default Input;
import React from "react";
import { View, Text, TextInput } from "react-native";
const Input = props => (
<View style={styles.inputRow}>
<View>
<Text style={styles.label}>{props.label}</Text>
</View>
<View>
<TextInput
style={styles.input}
autoCorrect={false}
secureTextEntry={props.secureTextEntry}
placeholder={props.placeholder}
value={props.value}
onChangeText={props.onChangeText}
/>
</View>
</View>
);
export default Input;
const styles = {
inputRow: {
flexDirection: "row",
height: 40,
width: 320,
marginBottom: 4,
justifyContent: "space-between",
alignItems: "center"
},
label: {
fontSize: 18,
alignSelf: "flex-start",
color: "teal"
},
input: {
color: "black",
paddingHorizontal: 5,
fontSize: 18,
alignSelf: "flex-end",
height: 24,
width: 230,
backgroundColor: "azure"
}
};
Now we'll combine these to make a form to enter the user's credentials.
import SubmitButton from "./SubmitButton";
import Input from "./Input";
import React, { useState } from "react";
LoginForm = props => {
const [ email, setEmail ] = useState( "" );
const [ password, setPassword ] = useState( "" );
<Input
label="Email"
value={ email }
placeholder="mary@example.com"
/>
<Input
label="Password"
value={ password }
placeholder="******"
secureTextEntry={ true }
/>
<SubmitButton whenPressed={ props.onSubmit }>
Login or Register!
</SubmitButton>
onChangeText={ email => setEmail( email ) }
...
onChangeText={ password => setPassword( password ) }
import React, { useState } from "react";
import { View, Text } from "react-native";
import SubmitButton from "./SubmitButton";
import Input from "./Input";
LoginForm = props => {
const [ email, setEmail ] = useState( "" );
const [ password, setPassword ] = useState( "" );
return (
<View>
<Input
label="Email"
value={ email }
placeholder="mary@example.com"
onChangeText={ email => setEmail( email )}
/>
<Input
label="Password"
value={ password }
placeholder="******"
secureTextEntry={ true }
onChangeText={ password => setPassword( password )}
/>
<SubmitButton whenPressed={ props.onSubmit }>
Login or Register!
</SubmitButton>
</View>
);
};
export default LoginForm;
Let's make the login form the first thing users see when opening the app.
import LoginForm from "../components/LoginForm";
import SubmitButton from "../components/SubmitButton";
const WelcomeScreen = () => {
return (
<View}>
<LoginForm />
</View>;
)
};
const WelcomeScreen = ({ navigation }) => {
return (
<SubmitButton
whenPressed={
() => navigation.navigate( "Pets" )
}
>
See lost pets
</SubmitButton>
);
} ;
We'll do this by writing an if statement in our JavaScript. It will test for a variable we'll call isLoggedIn that we'll change from false to true when the user logs in.
import React, { useState } from "react";
const WelcomeScreen = ({ navigation }) => {
if ( !isLoggedIn ) { // If the user isn't logged in.
return <LoginForm />;
}
else { // If the user is logged in.
return (
<SubmitButton
whenPressed={
() => navigation.navigate( "Pets" )
}
>
See lost pets
</SubmitButton>
);
};
};
But we still need to determine the value of isLoggedIn in WelcomeScreen.js even though it's set in the child component LoginForm.js. How do we pass information from a child component to its parent?
As we know from previous tutorials, you can pass data down to child component by writing custom properties, or "props," as attributes into the tag in the parent.
However, you can also pass data upwards, from the child to the parent, if one of those attributes is a function called in the child but defined in the parent. This is called "lifting the state up."
Fortunately, we can use the onSubmit listener we already built into <LoginForm> to trigger the change in LoginForm.js and have it percolate back to WelcomeScreen.js.
const [ isLoggedIn, setIsLoggedIn ] = useState( false );
const logInUser = () => {
setIsLoggedIn( true ) ;
};
return <LoginForm onSubmit={ logInUser } /> ;
import React, { useState } from "react";
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import { View, StyleSheet } from "react-native";
import LoginForm from "../components/LoginForm";
import SubmitButton from "../components/SubmitButton";
const WelcomeScreen = ({ navigation }) => {
const [ isLoggedIn, setIsLoggedIn ] = useState( false );
const logInUser = () => {
setIsLoggedIn( true );
};
if (!isLoggedIn ) {
return <LoginForm onSubmit={ logInUser } />;
} else {
return (
<SubmitButton whenPressed={() => navigation.navigate( "Pets" )}>
See lost pets
</SubmitButton>
);
}
};
export default WelcomeScreen;
const styles = StyleSheet.create({
welcomeContainer: {
flex: 1,
alignItems: "center",
justifyContent: "center",
backgroundColor: "paleturquoise"
}
});