When creating a mobile application, chances are at some point in time you’re going to want to have more than one application view or screen. In many programming languages this is referred to as application routes.
With React Native, the navigator is used to switch between screens.
Previously I wrote about how to change between views in Ionic Framework using the AngularJS UI-Router. This time we’ll be using the React Native NavigatorIOS component, but both will have similar goals.
Before going any further it is important to note that as of now React Native only works for iOS. This means you must be using a Mac computer to develop with.
With React Native already installed, execute the following from your Terminal:
react-native init ReactProject
No additional plugins or libraries are required at this point.
The application we are building will have two different screens. We’ll have a login screen that allows the user to enter a username and password and we’ll have a secure screen that just presents what the user has entered. We’re not actually doing any authentication because for this tutorial we’re only interested in navigation.
Open the project’s index.ios.js file and add the following code:
"use strict";
var React = require("react-native");
var {
AppRegistry,
StyleSheet,
Text,
View,
NavigatorIOS,
} = React;
var LoginView = require("./LoginView");
var ReactProject = React.createClass({
render: function() {
return (
<NavigatorIOS
style={styles.navigationContainer}
initialRoute={{
title: "Navigator Example",
component: LoginView,
}} />
);
}
});
var styles = StyleSheet.create({
navigationContainer: {
flex: 1
}
});
AppRegistry.registerComponent("ReactProject", () => ReactProject);
A few things to note about the root JavaScript file:
LoginView
class which we’ll create later. This is the first screen the user will seeNavigatorIOS
, giving the first screen a title, and setting the first screen as the LoginView
classWith that out of the way, let’s move on to the code for the LoginView
class. Create a file called LoginView.js at the root of your project and add the following code:
"use strict";
var React = require("react-native");
var {
Component,
StyleSheet,
Text,
TextInput,
TouchableHighlight,
View,
} = React;
var SecureView = require("./SecureView");
class LoginView extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: ""
};
}
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>
Sign In
</Text>
<View>
<TextInput
placeholder="Username"
onChange={(event) => this.setState({username: event.nativeEvent.text})}
style={styles.formInput}
value={this.state.username} />
<TextInput
placeholder="Password"
secureTextEntry={true}
onChange={(event) => this.setState({password: event.nativeEvent.text})}
style={styles.formInput}
value={this.state.password} />
<TouchableHighlight onPress={(this.onSubmitPressed.bind(this))} style={styles.button}>
<Text style={styles.buttonText}>Submit</Text>
</TouchableHighlight>
</View>
</View>
);
}
onSubmitPressed() {
this.props.navigator.push({
title: "Secure Page",
component: SecureView,
passProps: {username: this.state.username, password: this.state.password},
});
}
};
var styles = StyleSheet.create({
container: {
padding: 30,
marginTop: 65,
alignItems: "stretch"
},
title: {
fontSize: 18,
marginBottom: 10
},
formInput: {
height: 36,
padding: 10,
marginRight: 5,
marginBottom: 5,
marginTop: 5,
flex: 1,
fontSize: 18,
borderWidth: 1,
borderColor: "#555555",
borderRadius: 8,
color: "#555555"
},
button: {
height: 36,
flex: 1,
backgroundColor: "#555555",
borderColor: "#555555",
borderWidth: 1,
borderRadius: 8,
marginTop: 10,
justifyContent: "center"
},
buttonText: {
fontSize: 18,
color: "#ffffff",
alignSelf: "center"
},
});
module.exports = LoginView;
There is a lot going on here so lets break it down into smaller chunks.
var SecureView = require("./SecureView");
The above line includes the SecureView
class that we’re going to create soon. We are including it so that we can navigate to it.
Next we’re using a constructor to initialize some things:
constructor(props) {
super(props);
this.state = {
username: "",
password: ""
};
}
The props
variable we are passing is for any passed variables. We’re not passing any to the LoginView
, but we will be for the SecureView
in a moment. The username
and password
variables are being initialized as blank.
This brings us to the render
function. Instead of explaining everything, I’m just going to brush over the important part of this function:
<TextInput
placeholder="Username"
onChange={(event) => this.setState({username: event.nativeEvent.text})}
style={styles.formInput}
value={this.state.username} />
<TextInput
placeholder="Password"
secureTextEntry={true}
onChange={(event) => this.setState({password: event.nativeEvent.text})}
style={styles.formInput}
value={this.state.password} />
<TouchableHighlight onPress={(this.onSubmitPressed.bind(this))} style={styles.button}>
<Text style={styles.buttonText}>Submit</Text>
</TouchableHighlight>
The <TextInput>
tags have an onChange
method. Every time text is changed, we use a lambda function to set the state variable. This is important because the state variable is what will be passed to the next view.
The <TouchableHighlight>
tag calls the onSubmitPressed
function when clicked. This function is what navigates to a different route.
this.props.navigator.push({
title: "Secure Page",
component: SecureView,
passProps: {username: this.state.username, password: this.state.password},
});
We’re pushing a view into the history stack. The username
and password
states are passed as properties to the next route. The last part of this file is the styles, but we’re not going to worry too much about that as it isn’t an important part of this article.
Finally let’s take a look at our SecureView
class. Create a file called SecureView.js at the root of your project and add the following code:
"use strict";
var React = require("react-native");
var {
Component,
StyleSheet,
Text,
View,
} = React;
class SecureView extends Component {
constructor(props) {
super(props);
this.state = {
username: this.props.username,
password: this.props.password
};
}
render() {
return (
<View style={styles.container}>
<Text style={styles.heading}>
Welcome {this.props.username}!
</Text>
<Text style={styles.subheading}>
Your password is {this.props.password}
</Text>
</View>
);
}
};
var styles = StyleSheet.create({
container: {
padding: 30,
marginTop: 65,
alignItems: "center"
},
heading: {
marginBottom: 20,
fontSize: 18,
textAlign: "center",
color: "#656565"
},
subheading: {
color: "#cccccc"
}
});
module.exports = SecureView;
Like the LoginView
class, the SecureView
class is pretty large as well. To make it easier we’re going to look at it in parts.
This class isn’t structured too differently than the LoginView
class. The most important part of this is the constructor:
constructor(props) {
super(props);
this.state = {
username: this.props.username,
password: this.props.password
};
}
Notice that we’re setting the username
and password
state variables as whatever was passed in as properties. With the state variables set, we can show them on the screen in the render
function.
We’ll skip over the rest because we’ve seen it all before.
Above is what the application should look like.
At some point in time you’re going to want more than one screen in your React Native application. This can be accomplished with the navigator component and a selection of route files. Variables can easily be passed to different routes with the React Native navigator as well.