March 13, 2017 Best Practices for Building an App with React Native React native components offer a variety of advantages for teams building across platforms. Learn how to build a React Native sample app of your own. Denislav Ganchev React Native is a JavaScript framework created by Facebook for developing native mobile applications. It is based on React, the library for building user interfaces from declarative components on the web. React Native components offer a variety of advantages for teams building across platforms. Learn how React Native impacts development projects and how to build a sample app of your own. What Is React Native? React Native is basically a set of libraries, which provide access to the corresponding native APIs. This means applications built with the technology will have access to native platform features like camera, user location, etc. React Native applications, similar to React, use a mixture of JavaScript and XML-like syntax called JSX to express the user interface as a function of the current application state. Writing React Native components is very similar to writing React components on the web. For example, instead of using <div>, you’ll use the <View> component and instead of using <img />, you’ll use <Image>. In the past couple of years, the following frameworks — Titanium, Ionic, Cordova and Phonegap — offered the opportunity to build mobile applications using purely web technologies including HTML, CSS and JavaScript. This is a real advantage enabling developers to use the same skill set for writing mobile applications and developing for the web. Given the fact the same codebase could be used for multiple platforms with only minor modifications, these types of frameworks quickly emerged in the web community. React Native differs from these types of frameworks in that it’s using JavaScript components, which on the corresponding platform will be rendered as native UI widgets. While an application written with Cordova, for example, works by wrapping the content in a WebView resulting in UI elements that don’t quite feel native, React Native applications offer truly native experiences. With React Native, developers can have one set of skills and use it to build applications for multiple platforms. Currently, React Native supports iOS, Android and Universal Windows Platform. Who Is Using React Native? Given the fact that React Native is a relatively new technology, the adoption and usage are quite good. Facebook (iOS and Android applications, also in Ads Manager) Instagram Airbnb Walmart Bloomberg A more complete list of the businesses using React Native can be found here. How React Native Works The most surprising thing for seasoned mobile developers about React Native is that it’s actually truly native. Most of the popular solutions for building mobile applications with JavaScript use a Cordova library or a framework built on top of it, such as Ionic. With Cordova, you have access to native API’s, but the core of your application will be just HTML and JavaScript rendered in a WebView. While it is possible to reach the look and feel of the native UI this way, every Cordova application will struggle in performance, which is especially true for graphically-heavy applications and on the Android platform as a whole. This will lead to poor user experience and frustrated clients. With React Native your JavaScript-defined components will be rendered as native widgets using an abstraction layer called “bridge”, which invokes the actual rendering API on the host platform. Unlike on a Cordova-based application, your logic will still be in JavaScript, but the UI will be truly native. React Native libraries run the application in a separate thread using platform’s JavaScript engine, without blocking the main UI thread. This way, we have the benefits of smooth animation and native performance. There is a third thread, which is responsible for the layout creation. Styling components are completed through CSS syntax, which is written in JavaScript objects. To construct the layout, React Native uses a subset of Flexbox, which provides an efficient way to distribute space between components in a container. All of the library’s core components accept the style prop. One noticeable difference from CSS on the web is that the style names are camelCased, e.g. marginLeft. A good approach is to use Stylesheet.create method, which makes the code cleaner. import React from 'react'; import {StyleSheet} from 'react-native'; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#FFFFFF', paddingTop: 24 }, list: { flex: 1, flexDirection: 'row' }, listContent: { flex: 1, flexDirection: 'column' }, row: { flex: 1, padding: 42, borderWidth: 1, fontSize: 24, borderColor: '#DDDDDD' }, sectionDivider: { alignItems: 'center', padding: 8, backgroundColor: '#EEEEEE' }, row: { flex: 1, alignSelf: 'center', fontSize: 24 } }); Benefits of Using React Native Cross Platform Many businesses require mobile applications for both of the major platforms — iOS and Android. The usual approach is to build iOS applications using one of the native languages (Swift or Objective-C) and build Android applications using Java. The main disadvantage of that approach is businesses must pay for developing and maintaining two separate applications that do the same thing. With React Native, the application has shared a codebase. According to Facebook in their Ad Manager application, code reuse is 87%, which is a huge number. Another great feature is, if teams need a platform-specific component, you can easily import it into the application. The Platform module detects the platform where the application is running and can be used to add specific components into the app. import React from 'react'; import {Platform} from 'react-native'; const ExampleComponent = Platform.select({ ios: () => require('./IOSComponent'), android: () => require('./AndroidComponent') }) export default ExampleComponent; Native Code Developers can write native code if needed. React Native lets teams easily use native modules and connect them to an application. For example, if you have an existing native codebase, and you don’t want to implement it again in JavaScript, the code can be used as it is in a React Native application. Communication between application modules is done through events or through passing props. This is a powerful feature which exposes all the power of the underlying platform to React Native application. Smaller Learning Curve Unlike other frameworks, which requires teams to learn a long list of specific concepts and use cases, React (which is also valid for React Native since it’s basically React) uses pure JavaScript. As an example, let’s consider rendering a list of items in Ionic, which uses Angular and React Native. In Ionic, development teams must use ngRepeat directive. If filtering based on a condition is needed, $filter service must be used. Developers who aren’t familiar with Angular will have a lot of questions, based only on this simple example — what is ngRepeat; how do you use $filter; what is the syntax for filtering items; what is $scope? With React Native, developers will use existing knowledge on JavaScript fundamentals and will use native map and filter functions. Better, Smoother Developer Experience One of the strongest arguments for developing a React Native application from the developer standpoint is: Compared to standard iOS and Android development, React Native apps can be “instantly” refreshed without waiting to rebuild. Error reporting is quite good too, and debugging JavaScript code is possible through Chrome Developer Tools. Also, since JavaScript is transpiled, all the new features of the language are available for the developer, which can boost productivity. Efficiency React Native enables quick prototyping and a very high initial velocity. Implementing basic features is easy, and if needed, they can be extended with native code and native views. React Native Demo Application Tutorial In the following tutorial, we’ll create an app, which will let users browse through a list of employees and see details about them. Users will also be able to search for an employee by name. Download the source code for this React Native sample application for iOS called Employee. We’ll use data from https://randomuser.me. The app will look like the below example. Getting Started First, we will go through the process of installing React Native. React Native uses Node.js to build the JavaScript code. If you already have it installed on your computer, you can skip the next few steps. I’m using MacOS, but the following steps will be similar for Windows too. We’ll install Node.js using Homebrew. First, install Homebrew by following the instructions on its website. After Homebrew is successfully installed, install Node.js by typing the following in the Terminal. brew install node Next, we need to install watchman. Watchman is a file watcher module created by Facebook. React Native uses it to detect code changes in application files so the code can be rebuilt accordingly. brew install watchman Next, install React Native CLI by using npm, which is the node package manager. Note: They are packaged together. npm install react-native-cli -g From the Terminal, navigate to your working folder and init the project by running the following command: react-native init Employee The CLI will create the structure of our project. Starter React native app is in index.ios.js for iOS and index.android.js for Android. However, for the rest of this tutorial, we’ll be using only iOS files. After the creation of the application is done, open Employee.xcodeproj which is in an iOS folder in XCode and run the app. The JS code will be loaded from http://localhost:8081/index.ios.bundle and React Packager together with node server will run to handle the above request. On build complete, you should see the following screen in the simulator: The welcome screen gives us hints about how to open developer tools and how to reload the application, both of which can be done really simply by pressing Command + Control + Z and Command + R. Developing Our App Let’s get started. It will be a simple employee listing application with additional search functionality. We’ll focus on the logic and will spend less time on styling the components. The application structure has the following form: In the API folder for the sake of simplicity, we’ll mock all the data that we need for our application. Application building blocks (the components) are separated in containers and components folders. The idea behind this is simple, dividing application components into presentational and stateful components makes reusability much easier and enforces separation of concerns. All the components in the components folder are presentational. They impact how things look. Components in containers folder are the ones that handle data flow and mutations. Now open index.ios.js and add the following: /** * Sample React Native App */ import React from 'react'; import {AppRegistry} from 'react-native'; import App from './src/containers/App'; AppRegistry.registerComponent('Employee', () => App); AppRegistry defines the entry point to the application and provides the root component. Next, we will examine the application skeleton, the App.js container component. App.js import React, {Component} from 'react'; import { StyleSheet, TabBarIOS } from 'react-native'; import {bind} from '../utils/utils'; import EmployeesTab from './EmployeesTab'; import SearchTab from './SearchTab'; const employeesIcon = 'data:image/png;base64,...'; class App extends Component { constructor(props, context) { super(props, context); this.state = { selectedTab: 'employees' }; bind(this)('_searchOnPress', '_employeesOnPress'); } _employeesOnPress() { this.setState({ selectedTab: 'employees' }) } _searchOnPress() { this.setState({ selectedTab: 'search' }) } render() { return ( <TabBarIOS selectedTab={this.state.selectedTab}> <TabBarIOS.Item title="Employees" selected={this.state.selectedTab === 'employees'} icon={{uri: employeesIcon, scale: 3}} onPress={this._employeesOnPress}> <EmployeesTab /> </TabBarIOS.Item> <TabBarIOS.Item title="Search" selected={this.state.selectedTab === 'search'} systemIcon="search" onPress={this._searchOnPress}> <SearchTab /> </TabBarIOS.Item> </TabBarIOS> ) } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, }, instructions: { textAlign: 'center', color: '#333333', marginBottom: 5, }, }); export default App; The app will use Tab bar with two items in it – Employees and Search. To add this type of functionality, we’ll use TabBarIOS component, which is provided by React Native. For every tab that we need, we’ll create a TabBarIOS.Item component and pass as children our custom component which will handle the tab route(EmployeesTab and SearchTab components). Methods _employeesOnPress and _searchOnPress are passed as onPress handlers to the corresponding components, and they are responsible for handling the state for the selected tab. Adding Tab Components Let’s create EmployeesTab and SearchTab components. They are pretty similar and wrap the NavigatorIOS component, which creates the routes for the tabs. EmployeesTab.js import React from 'react'; import { NavigatorIOS, StyleSheet } from 'react-native'; import Employees from './Employees'; const EmployeesTab = ({props}) => ( <NavigatorIOS style={styles.container} initialRoute={{ title: 'Employees list', component: Employees }}/> ); const styles = StyleSheet.create({ container: { flex: 1 } }); export default EmployeesTab; SearchTab.js import React from 'react'; import { NavigatorIOS, StyleSheet } from 'react-native'; import Search from './Search'; const SearchTab = ({props}) => ( <NavigatorIOS style={styles.flex1} initialRoute={{ title: 'Search employees', component: Search }}/> ); const styles = StyleSheet.create({ flex1: { flex: 1 } }); export default SearchTab; Employees List View In the Employees container component, we will create the ListView with all the employees available. On componentDidMount lifecycle hook, which is called when a component is loaded/mounted onto the UI view, we are loading the data and setting up the dataSource for the ListView. Then, the data is passed via props to the EmployeesList presentational component, which is responsible for rendering the ListView. import React, {Component, PropTypes} from 'react'; import { StyleSheet, View, ListView, TouchableHighlight, NavigatorIOS } from 'react-native'; import {bind} from '../utils/utils'; import Employee from '../components/Employee'; import EmployeeDetails from '../components/EmployeeDetails'; class EmployeesList extends Component { constructor(props, context) { super(props, context); bind(this)('_renderRow', '_rowOnPress') } static propTypes = { dataSource: PropTypes.object.isRequired, navigator: PropTypes.object.isRequired }; _renderRow(rowData, sectionId, rowId, highlightRow) { const _rowHighlightOnPress = () => { this._rowOnPress(rowData); highlightRow(sectionId, rowId) }; return ( <TouchableHighlight onPress={_rowHighlightOnPress}> <View style={styles.flex1}> <Employee employee={rowData}/> </View> </TouchableHighlight> ) } _rowOnPress(employee) { this.props.navigator.push({ title: `${employee.name.first.toUpperCase()} ${employee.name.last.toUpperCase()}`, component: EmployeeDetails, passProps: {employee} }) } render() { return ( <ListView dataSource={this.props.dataSource} renderRow={this._renderRow}/> ) } } const styles = StyleSheet.create({ flex1: { flex: 1 } }); export default EmployeesList; Employees.js We use the ListView ReactNative component and pass *dataSource* and *renderRow* functions. *renderRow* is responsible for List item row appearance and behavior. We are using TouchableHighlight component, which is a wrapper for making views respond properly to touches. When a row is pressed, _rowOnPress is triggered, the opacity of the View is decreased, which allows the underlying color to show through, darkening or tinting the View. Also, a new route with (EmployeeDetails) props is pushed to the navigator object. import React, {Component} from 'react'; import { StyleSheet, Text, View, ListView, NavigatorIOS } from 'react-native'; import {bind} from '../utils/utils'; import EmployeesApi from '../api/mockEmployeesApi'; import EmployeesList from '../components/EmployeesList'; class Employees extends Component { constructor(props, context) { let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); super(props, context); this.state = { dataSource: ds.cloneWithRows([]), isLoading: true }; bind(this)('_renderLoadingView') } _renderLoadingView() { return ( <View> <Text>Loading...</Text> </View> ) } componentDidMount() { EmployeesApi.getAllEmployees() .then(function (data) { this.setState({ dataSource: this.state.dataSource.cloneWithRows(data), isLoading: false }) }.bind(this)); } render() { if (this.state.isLoading) { return this._renderLoadingView(); } return ( <View style={styles.container}> <EmployeesList dataSource={this.state.dataSource} navigator={this.props.navigator}/> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, paddingTop: 40 } }); export default Employees; EmployeeDetails.js import React, {PropTypes} from 'react'; import { View, Text, Image, StyleSheet } from 'react-native'; const EmployeeDetails = ({employee}) => ( <View style={styles.employee}> <Image style={styles.cover} source={{uri: employee.picture.large}}/> <View style={styles.info}> <Text style={styles.name}> {`${employee.name.first.toUpperCase()} ${employee.name.last.toUpperCase()}`} </Text> <Text> <Text style={styles.fontBold}>Phone: </Text> {employee.cell} </Text> <Text> <Text style={styles.fontBold}>Email: </Text> {employee.email} </Text> <Text> <Text style={styles.fontBold}>Location: </Text> {employee.location.city}, {employee.location.street} </Text> <Text> <Text style={styles.fontBold}>DOB: </Text> {employee.dob} </Text> </View> </View> ); EmployeeDetails.propTypes = { ...View.propTypes, employee: PropTypes.object.isRequired }; const styles = StyleSheet.create({ employee: { flex: 1, flexDirection: 'column', justifyContent: 'center', paddingTop: 40, padding: 5, backgroundColor: '#FFFFFF' }, cover: { flex: 1, height: 150, marginTop: 40, resizeMode: 'contain' }, info: { flex: 3, flexDirection: 'column', alignSelf: 'center', padding: 20 }, name: { alignSelf: 'center', marginBottom: 12, fontSize: 16, fontWeight: '700', color: '#222222' }, fontBold: { fontWeight: '700' } }); export default EmployeeDetails; Adding Search Now that we have completed all the routes for the Employees tab, we’ll work on the Search tab enabling the user to search Employees by name. Create a Search.js container component and add the following: import React, {Component} from 'react'; import { StyleSheet, ListView, TextInput, View, NavigatorIOS } from 'react-native'; import {bind} from '../utils/utils'; import EmployeesApi from '../api/mockEmployeesApi'; import EmployeesList from '../components/EmployeesList'; class Search extends Component { constructor(props, context) { let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); super(props, context); this.state = { text: 'Search by name', dataSource: ds.cloneWithRows([]) }; bind(this)('_searchInputOnChange', '_getAllEmployeesAndUpdateData') } componentDidMount() { this._getAllEmployeesAndUpdateData(); } _getAllEmployeesAndUpdateData() { EmployeesApi.getAllEmployees() .then(function (data) { this.setState({ dataSource: this.state.dataSource.cloneWithRows(data), isLoading: false }) }.bind(this)); } _searchInputOnChange(text) { if (text.length < 1) { this._getAllEmployeesAndUpdateData(); this.setState({ text }); } EmployeesApi.searchEmployeeByName(text) .then(function (res) { this.setState({ text, dataSource: this.state.dataSource.cloneWithRows(res) }) }.bind(this)) } render() { return ( <View style={styles.container}> <TextInput style={styles.searchInput} autoCorrect={false} clearTextOnFocus={true} value={this.state.text} onChangeText={this._searchInputOnChange}/> <EmployeesList dataSource={this.state.dataSource} navigator={this.props.navigator}/> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, paddingTop: 40 }, searchInput: { height: 44, margin: 10, marginTop: 30, padding: 10, borderWidth: 1, borderColor: '#CCCCCC' } }); export default Search; When the user types in the search box, we are querying the API, and the returned data is displayed. Notice that we are reusing the EmployeesList component to show the results, which is a great example of React Native components’ reusability. Finished App Screens Takeaways React Native is a relatively new technology, which already has great adoption. It increases developers’ productivity; it’s scalable and could save businesses time and money. Image Source: Unsplash, chuttersnap Tags MobileDevelopmentWebCross Platform Share Share on Facebook Share on LinkedIn Share on Twitter Dawn of the Progressive Web Apps What is a Progressive Web App, and what new options do they provide smart businesses? Download Share Share on Facebook Share on LinkedIn Share on Twitter Sign up for our monthly newsletter. Sign up for our monthly newsletter.