Mobile14 minute read

Dive into React Native for Android Development

Despite initial skepticism, React Native is very much in demand today!

In this article, Toptal Freelance React Native Developer, and former React Native skeptic, Alexander Pataridze talks about why he became a React Native advocate instead and introduces us to the technology by illustrating four use-cases.


Toptalauthors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.

Despite initial skepticism, React Native is very much in demand today!

In this article, Toptal Freelance React Native Developer, and former React Native skeptic, Alexander Pataridze talks about why he became a React Native advocate instead and introduces us to the technology by illustrating four use-cases.


Toptalauthors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.
Alexander Pataridze
Verified Expert in Engineering

Alex is a senior mobile developer with years of experience in Android and iOS. He created mobile banking suites and apps for several banks.

Read More

PREVIOUSLY AT

Bank of Georgia
Share

A few years ago, a coworker of mine told me about React Native. I was very skeptical. I argued that it is just another cross-platform framework which will never work in real life – little did I know how wrong I was.

Years passed and React Native skills became very much in demand. Since it’d been a while that I learned something new, I thought why not give it a shot? Today, I’m a React Native Android app development advocate.

Cons:

  • You can’t use Android Studio anymore
  • React Native can’t be used for every application or feature
  • React Native is a novel framework and updates can have a negative effect on your current codebase
  • JavaScript isn’t a strictly typed language
  • React Native requires a JavaScript engine to run, which may make it less performant

Pros:

  • Easy to learn
  • A shared codebase between Android and iOS apps, with only minor tweaks required to match platform experiences
  • Live and hot reloading, meaning no more infinite build times
  • Native components for both platforms
  • Constantly improving
  • Actively growing community
  • Huge number of libraries
  • Expo removes the need to own a Mac to develop for iOS
  • Reduction in labor resources—while you may still need some Android/iOS native development, it will be infrequent.

I can go on and on, but let’s stop here and move on to the topic of this blog post. In this post, I’m going to create four React Native Android apps:

  1. A basic counter with buttons to increment and decrement the counter
  2. An app to search the r/pics subreddit
  3. A generic login page
  4. An app to browse the r/pics subreddit

IDE

As I mentioned above, there’s no way we can use Android Studio for React Native development. We need a substitute. React Native can be developed probably in any modern text editor available out there (Atom, VS Code, Sublime Text, Brackets, etc.) but since we are coming with Android Studio experience my favorite is WebStorm which is built by the same company. Although WebStorm is paid application (129$ per year) you can install Early Access version of it. EAP build of WebStorm is free of charge and quite stable. If you prefer an editor which is completely free go for VS Code. Microsoft even developed amazing React Native plugin for it and it works very well.

Creating a New Project

Prerequisites: Android SDK, Node, and React Native installed on your computer.

There are two ways of creating new React Native project.

  1. The conventional way. Either with WebStorm GUI or with terminal command: react-native init AwesomeToptalProject
  2. Easier way “Create React Native App”. create-react-native-app AwesomeToptalProject

If you use create-react-native-app, the created project will be bootstrapped with expo. I won’t be going into details, but basically, it means that you have no need to have Xcode installed to run the app on iOS. It’s also easier to have the client always up-to-date through expo.io’s functionality and some other features. But you can’t add native code. Thus, if you are developing a specific feature, you may need to eject an app from expo and use a regular React Native project instead.

In this demonstration, I will be using the first method as I explain how to build a React Native app for Android.

Let’s run the project. First, open an emulator or connect the device. If you created the project with WebStorm GUI, all you need to do is to pick a configuration. In the right top corner of WebStorm, click the drop-down to the left of the Run button, choose Android, and click Run or Debug. If you created the project with Terminal, you can either add a new React Native config or run it using Terminal:

cd AwesomeToptalProject
react-native run-android

If everything went well, you’ll be greeted with the following screen:

Generated layout

Structure and Basic Setup

Notable items inside the project are:

  • android - Android Studio project preconfigured with React Native support.
  • ios - Xcode project preconfigured with React Native support.
  • node_modules - A folder containing React Native framework and other Javascript libraries.
  • index.js - An entry point for our app.
  • App.js - Initial component loaded.

Let’s create a folder “src” inside the root of the project and move App.js there. You’ll have to update index.js imports to match the new App.js location.

import App from './src/App';

Delete everything inside App.js and paste this code:

import React from 'react';
import {Text} from 'react-native';
export default class App extends React.Component {
   render() {
       return (
           <Text>Hello TopTal</Text>
       );
   }
}

The code we pasted is pretty straightforward. We created a class App (child of React.Component) which overrides render() method and returns Text component. React.Component is the base class for building UI using JSX. The export default modifier makes the class public.

We are now ready to start designing our layout.

Layout with Flexbox

Flexbox is similar to LinearLayout, but Flexbox goes way beyond LinearLayout’s abilities.

This snippet of JSX:

<View style={{
  flex: 1,
  flexDirection: 'row'
}}>
<View style={{
  width: 100, height: 100,
  backgroundColor: '#9575CD'
}}/>
<View style={{
  width: 100, height: 100,
  backgroundColor: '#7E57C2'
}}/>
<View style={{
  width: 100, height: 100,
  backgroundColor: '#673AB7'
}}/>
</View>

Renders this layout:

Generated layout

While this XML:

<LinearLayout
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="horizontal">
<View
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="#9575CD" />
<View
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="#7E57C2" />
<View
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="#673AB7" />
</LinearLayout>

Renders this:

Generated layout

JSX code looks familiar, huh?! Let’s create a “dictionary” (or a cheatsheet) for layouts using that look similar in JSX and Android XML.

Please note the functionalities aren’t necessarily equal. I’m trying to help the React Native newbies to grasp the idea of the layout system in React Native. Please refer official guide for detailed information.

Consider this JSX property:

flex: 1

It’s equivalent to this:

android:layout_width="match_parent"
android:layout_height="match_parent"

This snippet of JSX:

<View style={{flex: 1,
  flexDirection: 'row'}}>
<View style={{
  width: 100, height: 100,
  backgroundColor: '#9575CD'}}/>
<View style={{
  width: 100, height: 100,
  backgroundColor: '#7E57C2'}}/>
<View style={{
  width: 100, height: 100,
  backgroundColor: '#673AB7'}}/>
</View>

And this XML:

<LinearLayout
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="horizontal">
<View
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="#9575CD" />
<View
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="#7E57C2" />
<View
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="#673AB7" />
</LinearLayout>

Both generate this output:

Generated layout

Similarly, this JSX:

<View style={{flex: 1,
  flexDirection: 'column'}}>
<View style={{
  width: 100, height: 100,
  backgroundColor: '#9575CD'}}/>
<View style={{
  width: 100, height: 100,
  backgroundColor: '#7E57C2'}}/>
<View style={{
  width: 100, height: 100,
  backgroundColor: '#673AB7'}}/>
</View>

And this XML:

<LinearLayout
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">
<View
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="#9575CD" />
<View
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="#7E57C2" />
<View
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="#673AB7" />
</LinearLayout>

Generate this:

Generated layout

To achieve the right position inside the container, we most commonly will be using a combination of flexDirection, alignItems, and justifyContent properties.

This JSX:

<View style={{flex: 1,
  flexDirection: 'column',
  alignItems: 'center'}}>
<View style={{
  width: 100, height: 100,
  backgroundColor: '#9575CD'}}/>
<View style={{
  width: 100, height: 100,
  backgroundColor: '#7E57C2'}}/>
<View style={{
  width: 100, height: 100,
  backgroundColor: '#673AB7'}}/>
</View>

And this XML:

<LinearLayout
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:gravity="center_horizontal"
  android:orientation="vertical">
<View
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="#9575CD" />
<View
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="#7E57C2" />
<View
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="#673AB7" />
</LinearLayout>

Will produce this layout:

Generated layout

This JSX:

<View style={{flex: 1,
   flexDirection: 'column',
   justifyContent: 'center'}}>
   <View style={{
      width: 100, height: 100,
      backgroundColor: '#9575CD'}}/>
   <View style={{
      width: 100, height: 100,
      backgroundColor: '#7E57C2'}}/>
   <View style={{
      width: 100, height: 100,
      backgroundColor: '#673AB7'}}/>
</View>

And this XML

<LinearLayout
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:gravity="center_vertical"
   android:orientation="vertical">
   <View
       android:layout_width="100dp"
       android:layout_height="100dp"
       android:background="#9575CD" />
   <View
       android:layout_width="100dp"
       android:layout_height="100dp"
       android:background="#7E57C2" />
   <View
       android:layout_width="100dp"
       android:layout_height="100dp"
       android:background="#673AB7" />
</LinearLayout>

Will produce this layout:

Generated layout

This JSX:

<View style={{flex: 1,
   flexDirection: 'row',
   justifyContent: 'center'}}>
   <View style={{
      width: 100, height: 100,
      backgroundColor: '#9575CD'}}/>
   <View style={{
      width: 100, height: 100,
      backgroundColor: '#7E57C2'}}/>
   <View style={{
      width: 100, height: 100,
      backgroundColor: '#673AB7'}}/>
</View>

And this XML:

<LinearLayout
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:gravity="center_horizontal"
   android:orientation="horizontal">
   <View
       android:layout_width="100dp"
       android:layout_height="100dp"
       android:background="#9575CD" />
   <View
       android:layout_width="100dp"
       android:layout_height="100dp"
       android:background="#7E57C2" />
   <View
       android:layout_width="100dp"
       android:layout_height="100dp"
       android:background="#673AB7" />
</LinearLayout>

Will produce this layout:

Generated layout

This JSX:

<View style={{flex: 1,
   flexDirection: 'row',
   justifyContent: 'center',
   alignItems: 'center'}}>
   <View style={{
      width: 100, height: 100,
      backgroundColor: '#9575CD'}}/>
   <View style={{
      width: 100, height: 100,
      backgroundColor: '#7E57C2'}}/>
   <View style={{
      width: 100, height: 100,
      backgroundColor: '#673AB7'}}/>
</View>

and this XML:

<LinearLayout
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:gravity="center"
   android:orientation="vertical">
   <View
       android:layout_width="100dp"
       android:layout_height="100dp"
       android:background="#9575CD" />
   <View
       android:layout_width="100dp"
       android:layout_height="100dp"
       android:background="#7E57C2" />
   <View
       android:layout_width="100dp"
       android:layout_height="100dp"
       android:background="#673AB7" />
</LinearLayout>

Will produce this layout:

Generated layout

Lesson to be learned: if we have flexDirection: row', alignItems works on Y axis and justifyContent works on X axis. Everything is mirrored for flexDirection: column’ - justifyContent affects Y axis and alignItems affect Y axis.

justifyContent: 'flex-start'gravity="start|left"
alignItems: 'flex-start'gravity="start|left"
justifyContent: 'flex-end'gravity="end|right"
alignItems: 'flex-end'gravity="end|right"

Try it yourself. Set justifyContent value to space-around, space-between, and space-evenly.

State Management

For updating the application state, you are going to use React’s state variable. Whenever state is updated, render() is invoked.

Copy the code below to your app:

import React from 'react';
import {Button, Text, View} from 'react-native';
export default class App extends React.Component {
   /*
   Initialize state object
   with variable 'number'
   set to 0 and variable name
   with value of empty string
   */
   state = {number: 0};
   render() {
       return (
           <View style={{
               flexDirection: 'row',
               justifyContent: 'space-between',
               alignItems: 'center',
               flex: 1,
               padding: 20
           }}>
               <Button title='Decrement'
                       color='#e57373'
                       onPress={() => this.decrement()}/>
               <Text>
                   {/*
                    Text will be automatically
                    updated whenever state.number
                    has changed value
                    */}
                   Value = {this.state.number}
               </Text>
               <Button title='Increment'
                       color='#64B5F6'
                       {/*
                        Set listener for click
                        */}
                       onPress={() => this.increment()}/>
           </View>
       );
   }
   //Declaration of decrement function
   decrement() {
       //To update the state we need invoke this.setState
       //with new value for variable 'number'
       this.setState({number: this.state.number - 1});
   }
   increment() {
       this.setState({number: this.state.number + 1});
   }
}
Final decrement app

If you click the DECREMENT and INCREMENT buttons, you’ll see that the text is automatically updated for you. There’s no need to explicitly use textView.setText("Value " + number).

State functionality comes handy for multiple reasons:

  • Ease of obtaining the value—you always know where and how to obtain the value for a specific variable.
  • Data isn’t bound to specific widgets.
  • Having multiple widgets dependent upon the common value change.

Creating a Search App for /r/pics

Now that we’ve got a handle on the fundamentals, let’s create something a little more complex: a search app for /r/pics. Reddit provides a straightforward JSON API endpoint, so we won’t have to go on side-quests to get authentication for it to work right.

React Native provides a built-in Fetch API. Since most of us are probably used to Retrofit and its ease of use, we’ll be using axios. You can install axios through a terminal command

using yarn (My preferred method):

yarn add axios

or using npm:

npm install axios

Imports:

import React from 'react';
import {
   TextInput, View, Text, Image,
   ActivityIndicator, Platform, StyleSheet
} from 'react-native';
import axios from 'axios';
TextInput = EditText,
ActivityIndicator = ProgressBar
Platform - Platform detecting module
StyleSheet - Module for creating stylesheets and moving them away from JSX

Create the class:

export default class App extends React.Component {
}

To initialize state. We’ll need:

  • loading - For showing a progress bar.
  • error - To show if some error yielded when making a REST API request.
  • imgUrl - To preview the searched image.
  • text - search query.
state = {text: '', loading: false, error: null, imgUrl: null};

Add the JSX code. We have a vertical layout with TextInput and Image components.

render() {
   return (
       //Predefined style. See below
       <View style={styles.containerStyle}>
           {/*
            returnKeyType ~ imeOptions
            onSubmitEditing ~ et.OnEditorActionListener
           */}
           <TextInput
               style={styles.textInputStyle}
               placeholder="Enter text to search an image"
               returnKeyType='search'
               autoFocus={true}
               onChangeText={(text) => this.setState({text})}
               onSubmitEditing={() => this.searchPicture()}/>
           {/*
            Render error Image component
            if this.state.imgUrl is
            not equal to null
           */}
           {
               this.state.imgUrl &&
               <Image
                   source={{uri: this.state.imgUrl}}
                   style={{flex: 1}}/>
           }
       </View>
   );
}

New Stuff:

onChangeText={(text) => this.setState({text})}
onSubmitEditing={() => this.searchPicture()}
{
   this.state.imgUrl &&
   <Image
       source={{uri: this.state.imgUrl}}
       style={{flex: 1}}/>
}

The first method does similar work to EditText with the TextWatcher component. Let’s be honest, it is much nicer in React Native.

The second method is invoked when the return key is pressed on the keyboard (et.OnEditorActionListener) after it triggers searchPicture().

The Image is rendered when imgUrl is not null or undefined since the ‘&&’ operator doesn’t check for a second argument if the first is already false.

You may be wondering why this.state.imgUrl is false. Well, when using logical operators in JavaScript, anything except ‘’ (an empty string), 0, false, null, or undefined are true. There’s no need for a specific check.

searchPicture() {
   //Default state
   this.setState({loading: true, error: null, imgUrl: null});
   axios.get('https://www.reddit.com/r/pics/search.json', {
       params: { //the get param map
           restrict_sr: 'on', //search only /r/pics
           limit: 1, //limit to one search item
           sort: 'new', //sort by creation date
           q: this.state.text //our search query
       }
   }).then(response => { //promise is resolved and 'then' block is triggered
       //set state with new values
       this.setState({
           imgUrl: response.data.data.children[0]
               .data.preview.images[0].source.url,
           error: null, loading: false
       })
   }).catch(error => {//Some error occurred
       //set error
       this.setState({error: error.message, loading: false, imgUrl: null})
   })
}

Here we go. The application should work as expected now. Enter a search string and press return.

Final reddit search app

Since our application is also ready to render ActivityIndicator and errors, we need to add some more code after the Image component:

{
   //Separate method
   this.renderProgress()
}
{/*
Render error Text component
if this.state.error is
not equal to null
*/}
{
   this.state.error &&
   <Text style={{margin: 16, color: 'red'}}>
       {this.state.error}
   </Text>
}

You can move render components outside of main render() method, too:

renderProgress() {
   //If this.state.loading is true
   //return View containing a progressbar
   //View takes style array
   if (this.state.loading === true) {
       return (
           <View style={
               [styles.containerStyle,
                   {justifyContent: 'center'}]}>
               <ActivityIndicator color='#e57373'/>
           </View>
       );
   }
}

All is left are styles. Put these outside of the App class.

const styles = StyleSheet.create({
   containerStyle: {
       flexDirection: 'column',
       flex: 1,
       //Since React Native is cross platform
       //let's handle both platforms.
       //Add top margin to fix status bar overlap
       marginTop: Platform.OS === 'ios' ? 20 : 0,
   },
   textInputStyle: {
       marginLeft: 16,
       marginRight: 16,
       height: Platform.OS === 'ios' ? 30 : undefined
   }
});

We can now add some more tweaks like automatically opening the soft keyboard when the application is launched.

Please note there’s an easier way to make TextInput automatically focus (autoFocus={true} prop), but our React Native Android example won’t be using it.

Add reference to the TextInput with prop:

ref={ref => this.searchInput = ref}

And override componentDidMount() lifecycle method like this:

componentDidMount(){
   this.searchInput.focus();
}

Reload the app and the keyboard is automatically open for us.

Component Lifecycle Methods

We’ve already created a component, but let’s go through the life of a component.

Here’s React’s lifecycle flow:

  • constructor() - Constructor is always called when application is started
  • static _getDerivedStateFromProps_(props, state) - Called before render and after update. Returns object for updating the state. Return null to update nothing.
  • render() - Render is required for every React Component class. It is used to render View.
  • componentDidMount() - Is invoked after the component is rendered and mounted to the view tree.
  • shouldComponentUpdate(nextProps, nextState) - Called after state or props change. The return defaults to true after every state update. Invokes render() if returns true.
  • getSnapshotBeforeUpdate(prevProps, prevState) - Called just before rendered output is committed.
  • componentDidUpdate(prevProps, prevState, snapshot) - Called after after rendering new update. It is not called after the first render().
  • componentWillUnmount() - Called just before component is unmounted and destroyed.

Component lifecycle chart

Reusable Components

We often need to create reusable components when working on the project. There are two ways of creating a component:

  1. Creating a class which extends React.Component. This method should be used if we need lifecycle methods.
  2. By writing a function which returns View for a simpler syntax.

Since we have already created Component classes let’s create a function for this instance.

Suppose we need an analog to <CardView>. Create a “common” folder under ./src directory.

Create CardView.js.

import React from "react";
import {View} from "react-native";
export default CardView = (props) => {
   return (
       //Style will be merged from default containerStyle
       //and props.style. props.style attributes will override
       //values if parameters are same.
       <View style={{...styles.containerStyle, ...props.style}}>
           {/*
            props.children contain subviews
            add this line if the component is container
           */}
           {props.children}
       </View>
   );
};
const styles = {
   containerStyle: {
       borderRadius: 4,
       margin: 5,
       padding: 5,
       elevation: 5,
       shadowColor: 'black',
       shadowRadius: 5,
       shadowOpacity: 0.5,
       shadowOffset: {width: 0, height: 3},
       backgroundColor: 'white'
   }
};

LoginForm using our new CardView layout:

import React from "react";
import {TextInput, Platform, Button, StyleSheet} from "react-native";
import CardView from "../common/components/CardView";
export default class LoginForm extends React._Component _{
   render() {
       return (
    //Override default style
           <CardView style={{
               borderRadius: 4,
               backgroundColor: '#fff'
           }}>
               <TextInput
                   placeholder="Email"
                   style={styles.textInputStyle}/>
               <TextInput
                   placeholder="Password"
                   style={styles.textInputStyle}
                   secureTextEntry={true}/>
               <Button color="#841584"
                       title="Login"
                       onPress={() => console.log("onLoginPress")}
                       buttonStyle={styles.buttonStyle}/>
           </CardView>
       );
   }
}
const styles = StyleSheet.create({
   buttonStyle: {
       elevation: 5,
       height: 40
   },
   textInputStyle: {
       padding: 10,
       //Additional params to make
       //iOS inputs prettier
       ...Platform.select({
           ios: {
               borderRadius: 2,
               marginTop: 5,
               backgroundColor: '#eeeeee'
           }
       })
   }
});

Import the LoginForm class in the App class and wrap it with View

<View style={{flex: 1,  justifyContent: 'center'}}>
   <LoginForm/>
</View>

If you tweak parameters in the styles, you can get something that looks much nicer.

Final generated login form app

Navigation to different scenes is an essential part for most of the applications. We’re going to create a Reddit /r/pics browser app.

Creating navigation in React Native is fairly easy.

Prerequisites

  • Install react-navigation with yarn or npm
  • Install axios with yarn or npm

Let’s start by creating two different components.

Note: Most of the code below should already be familiar to you. I will paste the whole class.

PictureList.js:

import React from 'react';
import {
   ActivityIndicator, FlatList,
   Image, Text, TouchableHighlight, View
} from "react-native";
import axios from "axios";
import CardView from "../common/CardView";
export default class PictureList extends React.Component {
   state = {loading: true, error: null, posts: null};
   componentDidMount() {
       axios.get('https://www.reddit.com/r/pics.json')
           .then(response => {
               this.setState({
                   posts: response.data.data.children,
                   loading: false
               })
           }).catch(error => {
           this.setState({
               error: error.message,
               loading: false
           })
       })
   }
   render() {
       return (
           <View style={{flex: 1, justifyContent: 'center'}}>

                // FlatList ~ ListView
                // data - DataSource for the List
                // renderItem - function returns View item
                // keyExtractor - Unique id for items

               {this.state.posts &&
               <FlatList data={this.state.posts}
                         renderItem={this.renderItem.bind(this)}
                         keyExtractor={(item) => (item.data.id + '')}/>}
               {this.state.loading &&
               <ActivityIndicator size="large" color="#f4511e"/>}
           </View>
       );
   }
   navigateToPicture(title, url) {
       this.props.navigation.navigate('PicturePreview', {
           'title': title,
           'url': url
       })
   }
   renderItem(item) {
       //Destructuring values from item
       //Read more 'ES6 destructuring'
       const {data} = item.item;
       const {title} = data;
       const {url} = data.preview.images[0].source;
       return (
           //Clickable view
           <TouchableHighlight onPress={() =>
               this.navigateToPicture(title, url)}>
               {/Reusing our CardView/}
               <CardView>
                   <Image style={{height: 150}}
                          source={{uri: url}}/>
                   <Text style={{padding: 5}}>{title}</Text>
               </CardView>
           </TouchableHighlight>
       )
   }
}

PicturePreview.js:

import React from 'react';
import {Image} from "react-native";
export default class PicturePreview extends React.Component {
   //Destructure navigation
   //Set title to header
   static _navigationOptions = ({navigation}) => ({
       title: navigation.state.params.title
   });
   render() {
       const {url} = this.props.navigation.state.params;
       return (<Image style={{flex: 1}} source={{uri: url}}/>)
   }
}

The navigationOptions will be automatically be invoked by React-Navigation.

Now let’s move to App.js

Note: There are many navigation types in React-Navigation. Today, we’ll be focusing on StackNavigation. Please refer to official website for detailed info.

import React from 'react';
import {createStackNavigator} from "react-navigation";
import PictureList from "./components/PictureList";
import PicturePreview from "./components/PicturePreview";
export default class App extends React.Component {
   render() {
       return (
           <Router/>
       );
   }
}
//Customize the header_
const NavigationOptions = {
   headerTintColor: '#fff',
   headerStyle: {
       backgroundColor: '#f4511e',
   }
};
//Create the router.
const Router = createStackNavigator({
       //Name the screen
       'PictureList': {
           //Link the Component
           screen: PictureList,
           //Additional navigation options
           navigationOptions: {
               title: '/r/pics Browser',
               ...NavigationOptions
           }
       },
       'PicturePreview': {
           screen: PicturePreview,
           navigationOptions: NavigationOptions
       }
   }, {
       //Root
       initialRouterName: 'PictureList'
   }
);

As you can see, all we need to do is create a navigation router and make the app render it. If everything went well, we’ll have a functional Reddit /r/pics browser app.

Android:

Final browsing app in Android

iOS:

Final browsing app in iOS

React Native for Android Developers: Unconventional but Effective

Since I started programming, I have had purely mobile development experiences. But now I can code for pretty much anything with React: mobile, desktop, and web.

If you decide to start developing your next amazing application using React Native, you’ll find that it has its quirks and some bugs here and there, but React Native is very functional and ideal for most projects.

Understanding the basics

  • What do you mean by IDE?

    Integrated development environment, or code editor.

  • What apps use React Native?

    Many popular applications make use of React Native including Facebook, Tesla, Skype, Instagram, Uber, etc.

  • What programming language does React Native use?

    JavaScript

  • How do you layout UI in React Native?

    Flexbox is the way of creating layouts in React Native.

  • Is React Native native or hybrid?

    In short, neither. Code programming for React Native, which is JavaScript, isn’t really compiled to Java or Swift/Objective C. So it still needs JavaScript engine to run. However, the UI uses native components so it’s native for the user interface.

  • Is React Native a framework?

    Yes. React Native is a framework for building apps which have Native UI.

Hire a Toptal expert on this topic.
Hire Now
Alexander Pataridze

Alexander Pataridze

Verified Expert in Engineering

Tbilisi, Georgia

Member since June 5, 2018

About the author

Alex is a senior mobile developer with years of experience in Android and iOS. He created mobile banking suites and apps for several banks.

Read More
authors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.

PREVIOUSLY AT

Bank of Georgia

World-class articles, delivered weekly.

Subscription implies consent to our privacy policy

World-class articles, delivered weekly.

Subscription implies consent to our privacy policy

Join the Toptal® community.