React Native was developed by Facebook, along with the lines of the React framework. Instead of rendering components to a browser’s DOM, React Native (RN) invokes native APIs to create internal components that are handled through your JS code. There are some differences between the usual HTML elements and RN’s components, but they are not too hard to overcome. With this tool, you are actually building a native app that looks and behaves exactly like any other native application, except that you use a single language, JS, for both Android and iOS development.
In this article, we’ll see how to install and use React Native to build a mobile application. We will also see how to add development tools like ESLint, Flow, and Prettier.
Setting up a RN application
There are three ways to set up a RN application: manually, which you won’t want to do; secondly, with packages, using the react-native-cli command-line interface; or lastly, by using a package very similar to create-react-native-app (or CRAN).
We start by getting a command-line utility, which will include plenty of other packages:
npm install create-react-native-app -g
Afterward, we can create and run a simple project with just three commands:
create-react-native-app yourprojectname cd yourprojectname npm start
How it works…
When you run your app, it starts a server at your machine, at port 19000 or 19001, to which you will connect using the Expo application. You can download Expo from its official website, which is available for both Android or iOS. Install it by following the instructions onscreen:
When you open the Expo app for the first time, it will look like the following screenshot:
Note that both the phone and your machine must be in the same local network, and your machine must also allow connections to ports 19000 and 19001; you may have to modify your firewall for this to work.
After you use the Scan QR Code option, there will be some synchronization, and soon you’ll get to see your basic code running with no problems:
Furthermore, if you modify the App.js source code, the changes will be immediately reflected in your device, which means all is well! To make sure this happens, shake the phone to enable the debugging menu, and make sure that Live Reload and Hot Reloading are enabled. You’ll also require Remote JS Debugging for later. Your phone should look as follows:
Adding development tools
Next, we need to add all the development tools required. We want to have ESLint for code checking, Prettier for formatting, and Flow for data types. CRAN takes care of including Babel and Jest, so we won’t have to do anything for those two.
How to do it…
As opposed React, where we need to add a special rewiring package in order to work with specific configurations, in RN, we can just add some packages and configuration files, and we’ll be ready to go.
For ESLint, we’ll have quite a list of packages we want:
npm install --save-dev eslint eslint-config-recommended eslint-plugin-babel eslint-plugin-flowtype eslint-plugin-react eslint-plugin-react-native
We’ll require a separate .eslintrc file, as in the case with React. The appropriate contents include the following:
"parser": "babel-eslint", "parserOptions": "ecmaVersion": 2017, "sourceType": "module", "ecmaFeatures": "jsx": true , "env": "node": true, "browser": true, "es6": true, "jest": true, "react-native/react-native": true , "extends": [ "eslint:recommended", "plugin:flowtype/recommended", "plugin:react/recommended", "plugin:react-native/all" ], "plugins": ["babel", "flowtype", "react", "react-native"], "rules": "no-console": "off", "no-var": "error", "prefer-const": "error", "flowtype/no-types-missing-file-annotation": 0
Having completed that, ESLint is set to recognize our code, but we have to configure Flow as well:
npm install --save-dev flow flow-bin flow-coverage-report flow-typed
We’ll have to add a couple of lines to the scripts section of package.json:
"scripts": "start": "react-native-scripts start", . . . "flow": "flow", "addTypes": "flow-typed install" ,
Then, we have to initialize the working directories of Flow:
npm run flow init
The contents of the .flowconfig file look like this:
[ignore] .*/node_modules/.* [include] [libs] [lints] all=warn untyped-type-import=off unsafe-getters-setters=off [options] include_warnings=true [strict]
There’s not much to installing Prettier, all we need is an npm command, plus the .prettierrc file. For the former, just use the following command:
npm install --save-dev prettier
For configuration, we can use the contents of this .prettierrc file:
"tabWidth": 4, "printWidth": 75
How it works…
Let’s check that everything is OK. We’ll start by looking at the App.js file that was created by CRAN, and we can immediately verify that the tools work—because a problem is detected! Have a look at the following screenshot:
The rule that fails is a new one, from eslint-plugin-react-native: no-color-literals, because we are using constants in styling, which could prove to be a maintenance headache in the future. We can solve that by adding a variable, and we’ll use a type declaration to make sure Flow is also running. The new code should be as follows:
// Source file: App.original.fixed.js /* @flow */ import React from "react"; import StyleSheet, Text, View from "react-native"; export default class App extends React.Component render() return ( Open up App.js to start working on your app!Changes you make will automatically reload.Shake your phone to open the developer menu. ); const white: string = "#fff"; const styles = StyleSheet.create( container: flex: 1, backgroundColor: white, alignItems: "center", justifyContent: "center" );
Using native components
Working with RN is very much like working with React—there are components, state, props, life cycle events, and so on—but there is a key difference: your own components won’t be based on HTML but on specific RN ones. For instance, you won’t be using
We will start with an example of countries and regions page, which you can find in the book’s GitHub repository. Since we are using PropTypes, we’ll need that package. Install it with the following command:
npm install prop-types --save
Then, we’ll have to install some packages, starting with Redux and relatives. Actually, CRAN already includes redux and react-redux, so we don’t need those, but redux-thunk isn’t included. We can install it using the following command:
npm install react react-redux redux-thunk --save
We’ll also be using axios for async calls:
npm install axios --save
Our final step will be to run the server code (you can find it in the GitHub repo) so that our app will be able to do async calls. After downloading the server code from the GitHub repo, go to the directory, and just enter the following command:
Let’s now see how we can modify our code to make it appropriate for RN.
How to do it…
Since RN uses its own components, your HTML experience will be of little use. Here, we’ll see some changes, but in order to derive the full benefits of all of RN’s possibilities, you’ll have to study its components on your own.
Let’s start with the component, which is rather simple:
// Source file: src/regionsApp/regionsTable.component.js . . . render() if (this.props.list.length === 0) return ( No regions. ); else const ordered = [...this.props.list].sort( (a, b) => (a.regionName ordered.map(x => ( x.regionName )) );
Notice that there are no changes in the rest of the component, and all your React knowledge is still valid; you just have to adjust the output of your rendering method.
Next, we’ll change the component to use , which is sort of similar, but we’ll require some extra modifications. Let’s take a look at our component, highlighting the parts where changes are needed:
// Source file: src/regionsApp/countrySelect.component.js /* @flow */ import React from "react"; import PropTypes from "prop-types"; import View, Text, Picker from "react-native"; export class CountrySelect extends React.PureComponent any }> static propTypes = loading: PropTypes.bool.isRequired, currentCountry: PropTypes.string.isRequired, list: PropTypes.arrayOf(PropTypes.object).isRequired, onSelect: PropTypes.func.isRequired, getCountries: PropTypes.func.isRequired ; componentDidMount() if (this.props.list.length === 0) this.props.getCountries(); onSelect = value => this.props.onSelect(value); render() if (this.props.loading) return ( Loading countries... ); else const sortedCountries = [...this.props.list].sort( (a, b) => (a.countryName Country: sortedCountries.map(x => ( )) );
Lots of changes! Let’s go through them in the order they occur:
- An unexpected change: if you want a component to display its current value, you must set its selectedValue property; otherwise, even if the user selects a country, the change won’t be seen onscreen. We’ll have to provide an extra prop, currentCountry, which we’ll get from the store, so we can use it as the selectedValue for our list.
- The fired event when the user selects a value is also different; the event handler will be called directly with the chosen value, instead of with an event from which to work with event.target.value.
- We have to replace the element with , and provide a prompt text prop that will be used when the expanded list is shown onscreen.
- We have to use elements for the individual options, noting that the label to be displayed is now a prop.
Let’s not forget the change when connecting the list of countries to the store; we’ll only have to add an extra property to the getProps() function:
// Source file: src/regionsApp/countrySelect.connected.js const getProps = state => ( list: state.countries, currentCountry: state.currentCountry, loading: state.loadingCountries );
Now, all we need to do is see how the main app is set up. Our App.js code will be quite simple:
// Source file: App.js /* @flow */ import React from "react"; import Provider from "react-redux"; import store from "./src/regionsApp/store"; import Main from "./src/regionsApp/main"; export default class App extends React.PureComponent render() return ( );
This is pretty straightforward. The rest of the setup will be in the main.js file, which has some interesting details:
// Source file: src/regionsApp/main.js /* @flow */ import React from "react"; import View, StatusBar from "react-native"; import ConnectedCountrySelect, ConnectedRegionsTable from "."; export class Main extends React.PureComponent render() return ( );
Apart from the usage of wherever we would previously have used
How it works…
Just for variety, instead of using my mobile phone, as I did earlier in this article, I decided to use an emulated device. After starting the application with npm start, I started my device, and soon got the following:
If the user touches the element, a popup will be displayed, listing the countries that were received from our Node server, as shown in the following screenshot:
When the user actually taps on a country, the onValueChange event is fired, and after calling the server, the list of regions is displayed, as follows:
Everything works, and is using native components; great! By the way, if you were not very sure about the selectedValue problem we described, just omit that prop, and when the user picks on a country, you’ll get a bad result:
This article walked you through the installation and set up the process of React Native and other development tools for developing the mobile version of a web app.