Create a Youtube-integrated application using React Native

Create a Youtube-integrated application using React Native

While building certain types of mobile apps, you might need to have media files displayed in the app. In this tutorial, we will see how to integrate media from YouTube into our mobile apps.

Introduction

While building certain types of mobile apps, you might need to have media files displayed in the app. In this tutorial, we will see how to integrate media from YouTube into our mobile apps.

What we'll build

We will build a simple mobile app using React Native called OurTube which will pull videos from the new trailers on Rotten Tomato YouTube channel via the Youtube API and display them to the user. After displaying, we should also be able to tap on a video and have it play inside the app.

Prerequisites

A basic understanding of React and React Native is required for this tutorial.

Getting started

Youtube is a video sharing website and it allows users to upload, rate, like, dislike, comment on videos and a lot more. Youtube also allows users to live stream videos. Youtube is also used widely for video blogging, educational purposes, movies, and trailers, and so on. With the Youtube API, users can find, watch, and manage content on YouTube. It also allows you to add YouTube functionality to your website and mobile apps.

Obtaining your YouTube API key

To get started, the first step is to obtain our developer API key from the developer console. If you prefer a video tutorial, you can find a detailed video tutorial on how to obtain your developer API keys for YouTube here.

After obtaining your API key that should look like AIzaSy****DjoCmWdzH*****cZYjOVg8o******, we require the playlist ID we would like to fetch. To get the playlist ID:

  • Go to Rotten Tomatoes TV channel YouTube page -> New Trailers Playlist
  • Copy the URL from the address bar e.g <a href="https://www.youtube.com/playlist?list=PLTovKDoAy18KZ6sUQcmK2RDQeYkm2xUNt" target="_blank">https://www.youtube.com/playlist?list=PLTovKDoAy18KZ6sUQcmK2RDQeYkm2xUNt</a> and the playlist ID will be the string after the list query in the URL which is PLTovKDoAy18KZ6sUQcmK2RDQeYkm2xUNt
Setting up our React Native project

To get started, follow the official documentation on how to set up your computer for React Native development. If you already have your computer set up, you need to initiate and create the application project.

    $ react-native init OurTube

Once that is completed, we need to compile and build the application to make sure everything is working fine.

    // For ios
    $ react-native run-ios

    // For Android
    $ react-native run-android

Configure routing using react-native-router-flux

React-native-router-flux is a simple navigation API on top of React Navigation and it allows you to declare all application routes in stack and scenes for easy management and configuration. To get started with react-native-router-flux:

    $ npm install react-native-router-flux --save

Go ahead and create a route file and configure all application routing.

    $ touch Route.js

Route.js should be in the root directory of our OurTube App and the contents will look like:

    // Route.js
    import React, { Component } from 'react';
    import {Platform} from 'react-native';
    // import components from react-native-router-flux
    import {Router, Stack, Scene} from 'react-native-router-flux';
    // import our screens as components 
    import Home from './screens/Home';
    import WatchVideo from './screens/Video';
    export default class Routes extends Component<{}> {
      render() {
        return(
          <Router>
              <Stack key="root">
                <Scene key="home" component={Home} title="Playlist Videos" />
                <Scene key="watchvideo" component={WatchVideo} title="View Video"/>
              </Stack>
          </Router>
          )
      }
    }

The Router is the main routing component while a Stack is a group of Scenes with it's own navigator, so you can have multiple stacks for navigating. A Scene is the basic routing component for the main router and all Scene components require a key prop that must be unique and a key prop is used to call the screen transition and must be unique to all screens. We have created two scenes called home and watchvideo. The scenes will be called as actions in our Home and Video screens. More information can be found in the official documentation of React Native Router Flux. Update App.js file to look like:

    // App.js
    import React, { Component } from 'react';
    import {
      StyleSheet,
      View,
      StatusBar,
    } from 'react-native';
    import Routes from './Route';
    export default class App extends Component<{}> {
      render() {
        return (
          <View style={styles.container}>
            <StatusBar
              backgroundColor="#fff"
              barStyle="dark-content"
            />
            <Routes/>
          </View>
        );
      }
    }
    const styles = StyleSheet.create({
      container : {
        flex: 1,
      }
    }); 

Creating UI components

React Native offers inbuilt UI components and we'll be leveraging these inbuilt components. We will make use of components such as the FlatList, Text, and so on. Let's go ahead to create our project directories and files:

    $ mkdir screens && cd screens
    $ touch Home.js Video.js

``js // screens/Home.js import React, { Component } from 'react'; import { StyleSheet, SafeAreaView, FlatList, Text, TouchableOpacity } from 'react-native'; import {Actions} from 'react-native-router-flux'; const MAX_RESULT = 15; const PLAYLIST_ID = "PLScC8g4bqD47c-qHlsfhGH3j6Bg7jzFy-"; const API_KEY = ""; export default class Home extends Component<{}> {

  home(){
    Actions.home();
  }
  watchVideo(video_url){
    Actions.watchvideo({video_url: video_url});
  }
  componentWillMount() {
    this.fetchPlaylistData();
  }
  fetchPlaylistData = async () => {
    const response = await fetch(`https://www.googleapis.com/youtube/v3/playlistItems?playlistId=${PLAYLIST_ID}&maxResults=${MAX_RESULT}&part=snippet%2CcontentDetails&key=${API_KEY}`);
    const json = await response.json();
    this.setState({ videos: json['items']});
    console.log(this.state.videos)
  };
  constructor(props) {
    super(props);
    this.state = {
      videos: [],
    }
  }
  render() {
    const videos = this.state.videos;
    return (
      <SafeAreaView style={styles.safeArea}>
            <FlatList
              data={this.state.videos}
              keyExtractor={(_, index) => index.toString()}
              renderItem={
                ({item}) => 
                <TouchableOpacity
                    style={styles.demacate}
                    onPress={() => this.watchVideo(item.contentDetails.videoId)}
                >
                <Text 
                  style={styles.item} 
                > 
                {item.snippet.title} 
                </Text>
                </TouchableOpacity>
              }
            />
      </SafeAreaView>
    );
  }
}
const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: '#fff'
  },
  demacate: {
    borderBottomColor: 'blue',
    borderBottomWidth: 2,
    borderRadius:10
  },
  item: {
    padding: 10,
    fontSize: 12,
    height: 44,
  },
});

The first thing we do in the `Home.js` file is to import all the necessary components to build the home screen. Like the variable names imply, `MAX_RESULT` is the number of videos we want to return from the youtube API, `PLAYLIST_ID` is a string of the youtube playlist we want to fetch and `API_KEY` will hold our Youtube API access key.

The `home()` and `watchVideo()` functions will call navigation actions that allow us to navigate from page to page. The `fetchPlaylistData()` is an asynchronous function that allows us to fetch data from the Youtube API and `componentWillMount()` allows us to fetch the async data after the screen is rendered. 

The response data is converted to JSON and stored in the videos state and will be passed to our component during rendering. 

In the `render()` we define a prop that holds data fetched such as video id from our Youtube API and we pass it to the videos page as a `video_url` prop so we don't have to do a network fetch to get the same data on the next screen. 

Our `render()` function renders the screen and we use the SafeAreaView component to handle the screens of newer devices such as the iPhone X, XR and higher so the screen doesn't overlap. We use the `Flatlist` component to render our data from the `videos` state using the `renderItem` prop.

```js
    // screens/Video.js
    import React, { Component } from 'react';
    import { StyleSheet, SafeAreaView, View, WebView } from 'react-native';
    import {Actions} from 'react-native-router-flux';
    export default class WatchVideo extends Component<{}> {

      home(){
        Actions.home();
      }
      videos(){
        Actions.videos();
      }
      constructor(props) {
        super(props);
        console.log(this.props);
      }
      render() {
        return (
          <SafeAreaView style={styles.safeArea}>
              { 
                <WebView
                  source={{ uri: "https://www.youtube.com/embed/"+this.props.video_url}}
                  startInLoadingState={true} 
                />
              }
          </SafeAreaView>
        );
      }
    }
    const styles = StyleSheet.create({
      safeArea: {
        flex: 1,
        backgroundColor: '#fff'
      }
    });

In the Video.js file, we also import all the necessary components to build our interface and likewise, create routing actions so we can navigate back to our home screen. In the render() function, the data we stored in the video_url props is accessed and rendered using the Webview video component. The component is customizable and allows us to define the URL source, loaders, and so on.

Building our app

To build and compile our code on iOS:

    $ react-native run-ios

To build and compile our code on Android:

    $ react-native run-android

After build is successful, your application should look like:

  • Home Screen
  • Video Screen
Conclusion

The YouTube API is robust and allows us to watch videos, get video metadata, and so on. The data can be integrated with any mobile development framework and as seen in OurTube app using React Native. OurTube app is in a simple version right now, but you can go ahead to add some more functionalities such as liking and disliking videos, reporting comments, and so on by reading the Google Developer guide for Youtube in order to build complex and robust applications. The codebase to this tutorial is available in a public GitHub repository. Feel free to play around with it.

Thanks for reading ❤

React Native Map components for iOS + Android

React Native Map components for iOS + Android

React Native Map components for iOS + Android.Contribute to react-native-community/react-native-maps development by creating an account on GitHub

React Native Map components for iOS + Android

Installation

See Installation Instructions.

See Setup Instructions for the Included Example Project.

Compatibility

Due to the rapid changes being made in the React Native ecosystem, we are not officially going to support this module on anything but the latest version of React Native. With that said, we will do our best to stay compatible with older versions as much that is practical, and the peer dependency of this requirement is set to "react-native": "*" explicitly for this reason. If you are using an older version of React Native with this module though, some features may be buggy.

Note about React requires

Since react-native 0.25.0, React should be required from node_modules. React Native versions from 0.18 should be working out of the box, for lower versions you should add react as a dependency in your package.json.

General Usage
source-js
import MapView from 'react-native-maps';

or

source-js
var MapView = require('react-native-maps');

This MapView component is built so that features on the map (such as Markers, Polygons, etc.) are specified as children of the MapView itself. This provides an intuitive and react-like API for declaratively controlling features on the map.

Rendering a Map with an initial region

MapView
source-js-jsx
  <MapView
    initialRegion={{
      latitude: 37.78825,
      longitude: -122.4324,
      latitudeDelta: 0.0922,
      longitudeDelta: 0.0421,
    }}
  />

Using a MapView while controlling the region as state

source-js-jsx
getInitialState() {
  return {
    region: {
      latitude: 37.78825,
      longitude: -122.4324,
      latitudeDelta: 0.0922,
      longitudeDelta: 0.0421,
    },
  };
}

onRegionChange(region) {
  this.setState({ region });
}

render() {
  return (
    <MapView
      region={this.state.region}
      onRegionChange={this.onRegionChange}
    />
  );
}

Rendering a list of markers on a map

source-js-jsx
import { Marker } from 'react-native-maps';

<MapView
  region={this.state.region}
  onRegionChange={this.onRegionChange}
>
  {this.state.markers.map(marker => (
    <Marker
      coordinate={marker.latlng}
      title={marker.title}
      description={marker.description}
    />
  ))}
</MapView>

Rendering a Marker with a custom view

source-js-jsx
<Marker coordinate={marker.latlng}>
  <MyCustomMarkerView {...marker} />
</Marker>

Rendering a Marker with a custom image

source-js-jsx
<Marker
  coordinate={marker.latlng}
  image={require('../assets/pin.png')}
/>

Rendering a custom Marker with a custom Callout

source-js-jsx
import { Callout } from 'react-native-maps';

<Marker coordinate={marker.latlng}>
  <MyCustomMarkerView {...marker} />
  <Callout>
    <MyCustomCalloutView {...marker} />
  </Callout>
</Marker>

Draggable Markers

source-js-jsx
<MapView initialRegion={...}>
  <Marker draggable
    coordinate={this.state.x}
    onDragEnd={(e) => this.setState({ x: e.nativeEvent.coordinate })}
  />
</MapView>

Using a custom Tile Overlay

Tile Overlay using tile server

source-js-jsx
import { UrlTile } from 'react-native-maps';

<MapView
  region={this.state.region}
  onRegionChange={this.onRegionChange}
>
  <UrlTile
    /**
     * The url template of the tile server. The patterns {x} {y} {z} will be replaced at runtime
     * For example, http://c.tile.openstreetmap.org/{z}/{x}/{y}.png
     */
    urlTemplate={this.state.urlTemplate}
    /**
     * The maximum zoom level for this tile overlay. Corresponds to the maximumZ setting in
     * MKTileOverlay. iOS only.
     */
    maximumZ={19}
    /**
     * flipY allows tiles with inverted y coordinates (origin at bottom left of map)
     * to be used. Its default value is false.
     */
    flipY={false}
  />
</MapView>

For Android: add the following line in your AndroidManifest.xml

text-xml
<uses-permission android:name="android.permission.INTERNET" />

For IOS: configure App Transport Security in your app

Tile Overlay using local tiles

Tiles can be stored locally within device using xyz tiling scheme and displayed as tile overlay as well. This is usefull especially for offline map usage when tiles are available for selected map region within device storage.

source-js-jsx
import { LocalTile } from 'react-native-maps';

<MapView
  region={this.state.region}
  onRegionChange={this.onRegionChange}
>
  <LocalTile
   /**
    * The path template of the locally stored tiles. The patterns {x} {y} {z} will be replaced at runtime
    * For example, /storage/emulated/0/mytiles/{z}/{x}/{y}.png
    */
   pathTemplate={this.state.pathTemplate}
   /**
    * The size of provided local tiles (usually 256 or 512).
    */
   tileSize={256}
  />
</MapView>

For Android: LocalTile is still just overlay over original map tiles. It means that if device is online, underlying tiles will be still downloaded. If original tiles download/display is not desirable set mapType to 'none'. For example:

<MapView
  mapType={Platform.OS == "android" ? "none" : "standard"}
>

See OSM Wiki for how to download tiles for offline usage.

Overlaying other components on the map

Place components you that wish to overlay MapView underneath the MapView closing tag. Absolutely position these elements.

source-js-jsx
render() {
  return (
    <MapView
      region={this.state.region}
    />
    <OverlayComponent
      style={{position: “absolute”, bottom: 50}}
    />
  );
}

Customizing the map style

Create the json object, or download a generated one from the google style generator.

source-js-jsx
// The generated json object
mapStyle = [ ... ]

render() {
  return (
    <MapView
      region={this.state.region}
      onRegionChange={this.onRegionChange}
      customMapStyle={mapStyle}
    />
  );
}

For iOS, in addition to providing the mapStyle you will need to do the following

source-js-jsx
import MapView, { PROVIDER_GOOGLE } from 'react-native-maps'

// ...

<MapView
  provider={PROVIDER_GOOGLE}
  customMapStyle={MapStyle}
>

Then add the AirGoogleMaps directory:

https://github.com/react-native-community/react-native-maps/blob/1e71a21f39e7b88554852951f773c731c94680c9/docs/installation.md#ios

An unofficial step-by-step guide is also available at https://gist.github.com/heron2014/e60fa003e9b117ce80d56bb1d5bfe9e0

Examples

To run examples:

source-shell
npm i
npm start

#Android
npm run run:android

#iOS
npm run build:ios
npm run run:ios

MapView Events

The <MapView /> component and its child components have several events that you can subscribe to. This example displays some of them in a log as a demonstration.

Tracking Region / Location

Programmatically Changing Region

One can change the mapview's position using refs and component methods, or by passing in an updated region prop. The component methods will allow one to animate to a given position like the native API could.

Changing the style of the map

Arbitrary React Views as Markers

Using the MapView with the Animated API

The <MapView /> component can be made to work with the Animated API, having the entire region prop be declared as an animated value. This allows one to animate the zoom and position of the MapView along with other gestures, giving a nice feel.

Further, Marker views can use the animated API to enhance the effect.

Issue: Since android needs to render its marker views as a bitmap, the animations APIs may not be compatible with the Marker views. Not sure if this can be worked around yet or not.

Markers' coordinates can also be animated, as shown in this example:

Polygon Creator

Other Overlays

So far, <Circle />, <Polygon />, and <Polyline /> are available to pass in as children to the <MapView /> component.

Gradient Polylines (iOS MapKit only)

Gradient polylines can be created using the strokeColors prop of the <Polyline> component.

Default Markers

Default markers will be rendered unless a custom marker is specified. One can optionally adjust the color of the default marker by using the pinColor prop.

Custom Callouts

Callouts to markers can be completely arbitrary react views, similar to markers. As a result, they can be interacted with like any other view.

Additionally, you can fall back to the standard behavior of just having a title/description through the <Marker />'s title and description props.

Custom callout views can be the entire tooltip bubble, or just the content inside of the system default bubble.

To handle press on specific subview of callout use <CalloutSubview /> with onPress. See Callouts.js example.

Image-based Markers

Markers can be customized by just using images, and specified using the image prop.

Draggable Markers

Markers are draggable, and emit continuous drag events to update other UI during drags.

Lite Mode ( Android )

Enable lite mode on Android with liteMode prop. Ideal when having multiple maps in a View or ScrollView.

On Poi Click (Google Maps Only)

Poi are clickable, you can catch the event to get its information (usually to get the full detail from Google Place using the placeId).

Animated Region

The MapView can accept an AnimatedRegion value as its region prop. This allows you to utilize the Animated API to control the map's center and zoom.

source-js-jsx
import MapView, { AnimatedRegion, Animated } from 'react-native-maps';

getInitialState() {
  return {
    region: new AnimatedRegion({
      latitude: LATITUDE,
      longitude: LONGITUDE,
      latitudeDelta: LATITUDE_DELTA,
      longitudeDelta: LONGITUDE_DELTA,
    }),
  };
}

onRegionChange(region) {
  this.state.region.setValue(region);
}

render() {
  return (
    <Animated
      region={this.state.region}
      onRegionChange={this.onRegionChange}
    />
  );
}

Animated Marker Position

Markers can also accept an AnimatedRegion value as a coordinate.

source-js-jsx
import Mapview, { AnimatedRegion, Marker } from 'react-native-maps';

getInitialState() {
  return {
    coordinate: new AnimatedRegion({
      latitude: LATITUDE,
      longitude: LONGITUDE,
    }),
  };
}

componentWillReceiveProps(nextProps) {
  const duration = 500

  if (this.props.coordinate !== nextProps.coordinate) {
    if (Platform.OS === 'android') {
      if (this.marker) {
        this.marker._component.animateMarkerToCoordinate(
          nextProps.coordinate,
          duration
        );
      }
    } else {
      this.state.coordinate.timing({
        ...nextProps.coordinate,
        duration
      }).start();
    }
  }
}

render() {
  return (
    <MapView initialRegion={...}>
      <MapView.Marker.Animated
        ref={marker => { this.marker = marker }}
        coordinate={this.state.coordinate}
      />
    </MapView>
  );
}

If you need a smoother animation to move the marker on Android, you can modify the previous example:

source-js-jsx
// ...

componentWillReceiveProps(nextProps) {
  const duration = 500

  if (this.props.coordinate !== nextProps.coordinate) {
    if (Platform.OS === 'android') {
      if (this.marker) {
        this.marker._component.animateMarkerToCoordinate(
          nextProps.coordinate,
          duration
        );
      }
    } else {
      this.state.coordinate.timing({
        ...nextProps.coordinate,
        duration
      }).start();
    }
  }
}

render() {
  return (
    <MapView initialRegion={...}>
      <Marker.Animated
        ref={marker => { this.marker = marker }}
        coordinate={this.state.coordinate}
      />
    </MapView>
  );
}

Take Snapshot of map

source-js-jsx
import MapView, { Marker } from 'react-native-maps';

getInitialState() {
  return {
    coordinate: {
      latitude: LATITUDE,
      longitude: LONGITUDE,
    },
  };
}

takeSnapshot () {
  // 'takeSnapshot' takes a config object with the
  // following options
  const snapshot = this.map.takeSnapshot({
    width: 300,      // optional, when omitted the view-width is used
    height: 300,     // optional, when omitted the view-height is used
    region: {..},    // iOS only, optional region to render
    format: 'png',   // image formats: 'png', 'jpg' (default: 'png')
    quality: 0.8,    // image quality: 0..1 (only relevant for jpg, default: 1)
    result: 'file'   // result types: 'file', 'base64' (default: 'file')
  });
  snapshot.then((uri) => {
    this.setState({ mapSnapshot: uri });
  });
}

render() {
  return (
    <View>
      <MapView initialRegion={...} ref={map => { this.map = map }}>
        <Marker coordinate={this.state.coordinate} />
      </MapView>
      <Image source={{ uri: this.state.mapSnapshot.uri }} />
      <TouchableOpacity onPress={this.takeSnapshot}>
        Take Snapshot
      </TouchableOpacity>
    </View>
  );
}

Zoom to Specified Markers

Pass an array of marker identifiers to have the map re-focus.

Zoom to Specified Coordinates

Pass an array of coordinates to focus a map region on said coordinates.

Troubleshooting

My map is blank

  • Make sure that you have properly installed react-native-maps.
  • Check in the logs if there is more informations about the issue.
  • Try setting the style of the MapView to an absolute position with top, left, right and bottom values set.
  • Make sure you have enabled Google Maps API in Google developer console
source-js
const styles = StyleSheet.create({
  map: {
    ...StyleSheet.absoluteFillObject,
  },
});
source-js-jsx
<MapView
  style={styles.map}
  // other props
/>

Inputs don't focus

  • When inputs don't focus or elements don't respond to tap, look at the order of the view hierarchy, sometimes the issue could be due to ordering of rendered components, prefer putting MapView as the first component.

Bad:

source-js-jsx
<View>
  <TextInput/>
  <MapView/>
</View>

Good:

source-js-jsx
<View>
  <MapView/>
  <TextInput/>
</View>

React Native Maps Tutorial | Add Google Maps to iOS & Android Apps

React Native Maps Tutorial | Add Google Maps to iOS & Android Apps

In this react native tutorial, you'll learn to integrate Google maps to your react native app using react-native-maps package. It is a complete step by step guide to add Google maps to your iOS & Android apps developed by react native

In this react native tutorial, you'll learn to integrate Google maps to your react native app using react-native-maps package. It is a complete step by step guide to add Google maps to your iOS & Android apps developed by react native. Here I have shown you a manual installation process without expo.

React Native Maps Package GitHub link https://github.com/react-native-community/react-native-maps

React Native Tutorial - Build Android and iOS App from Scratch

React Native Tutorial - Build Android and iOS App from Scratch

React Native Tutorial - Build Android and iOS App from Scratch. Getting started tutorial on building an Android and iOS app from scratch using React Native. React Native is a modern Javascript framework backed by Facebook that use to make Mobile Apps (Android/iOS) development easier for Javascript developer. In other words, React Native is React.js mobile apps development version.

A comprehensive step by step tutorial on building Android and iOS app from scratch using React Native

A comprehensive getting started tutorial on building an Android and iOS app from scratch using React Native. React Native is a modern Javascript framework backed by Facebook that use to make Mobile Apps (Android/iOS) development easier for Javascript developer. In other words, React Native is React.js mobile apps development version. For more information about React Native definition, features, etc, you can find in their official documentation.

Shortcut to the steps:

  • Install React App Creator and Create A React Native App
  • Add Navigation Header and Home Screen
  • Load World Cup 2018 Data from API
  • Display List of World Cup Matchdays
  • Display World Cup 2018 Matchdays Details
  • Run the React Native World Cup 2018 App

In this React Native tutorial, we are creating an app that listing the World Cup 2018 matches using the free open public domain football data for the world cups in the JSON format.

The following tools, frameworks, and modules are required for this tutorial:

  • React Native
  • Node.js (NPM or Yarn)
  • Worldcup JSON data
  • Android Studio or SDK for Android
  • XCode for iOS
  • Terminal (OSX/Linux) or Command Line (Windows)
  • Text Editor or IDE (We are using Atom)

Before start to the main steps, make sure that you have installed Node.js and can run npm in the terminal or command line. To check existing or installed Node.js environment open the terminal/command line then type this command.

node -v
v8.11.1
npm -v
6.1.0
yarn -v
1.7.0

That's the Node and NPM or YARN version that we are using. In this tutorial, we will use Yarn commonly.

Install React App Creator and Create A React Native App

The Create React Native App is a tool for creating a React Native App. To install it, type this command in your App projects folder.

sudo npm install -g create-react-native-app

Then create a React Native App using this command.

create-react-native-app reactWorldCupApp

That command will create a React Native app then install all required modules. The app or project folder will contain these folders and files.

Next, go to the newly created React App folder.

cd reactWorldCupApp

This React Native App is running via Expo app, before running on your Android or iOS device, make sure you have to install the Expo App to Android or Expo Client to iOS. Of course, that app is available in the App Store. So, we assume that you have installed the Expo App in your device then type this command to run the app.

npm start

or

yarn start

You will see this barcode and instruction in the terminal or command line.

To open the app in the Android device, open the Expo App first then tap on Scan QR Code button. Scan the barcode in the terminal or command line then you will see the React Native Android App like this after waiting for minutes the build process.

For iOS Device, press s from the keyboard to send React Native App URL to your Email or SMS. Enter your phone number or Email address (We use an email address) then press Enter. You will get this email to your mailbox.

Choose open in Expo URL then open in your browser, that will be redirected to Expo App. In Expo App welcome screen, shake your phone to open the React Native App. Now, you will see this screen in your iOS device.

This step for development purpose, we will show you how to build for production at the end of this article.

Add Navigation Header and Home Screen

Above generated React Native App just show blank app with plain text. Now, we will show you how to add the Navigation Header and Home Screen for your app. So, it will look like the Native App. In the terminal or command line type this command to install React Navigation (react-navigation) module.

yarn add react-navigation

Next, create a folder for components and React Native components files in the root of the app folder.

mkdir components
touch components/HomeScreen.js
touch components/DetailsScreen.js

Open and edit components/HomeScreen.js then add this React Native codes.

import React, { Component } from 'react';
import { Button, View, Text } from 'react-native';

class HomeScreen extends Component {
  static navigationOptions = {
    title: 'Home',
  };
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Home Screen</Text>
        <Button
          title="Go to Details"
          onPress={() => this.props.navigation.navigate('Details')}
        />
      </View>
    );
  }
}

export default HomeScreen;

Open and edit components/DetailsScreen.js then add this React Native codes.

import React, { Component } from 'react';
import { Button, View, Text } from 'react-native';

class DetailsScreen extends Component {
  static navigationOptions = {
    title: 'Details',
  };
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Details Screen</Text>
        <Button
          title="Go to Details... again"
          onPress={() => this.props.navigation.push('Details')}
        />
        <Button
          title="Go to Home"
          onPress={() => this.props.navigation.navigate('Home')}
        />
        <Button
          title="Go back"
          onPress={() => this.props.navigation.goBack()}
        />
      </View>
    );
  }
}

export default DetailsScreen;

Next, open and edit App.js then add replace all codes with this.

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { createStackNavigator } from 'react-navigation';
import HomeScreen from './components/HomeScreen';
import DetailsScreen from './components/DetailsScreen';

const RootStack = createStackNavigator(
  {
    Home: HomeScreen,
    Details: DetailsScreen,
  },
  {
    initialRouteName: 'Home',
    navigationOptions: {
      headerStyle: {
        backgroundColor: '#f4511e',
      },
      headerTintColor: '#fff',
      headerTitleStyle: {
        fontWeight: 'bold',
      },
    },
  },
);

export default class App extends React.Component {
  render() {
    return <RootStack />;
  }
}

When the files are saved, the Expo app will refresh the React Native App automatically. Now, the app will look like this.

Load World Cup 2018 Data from API

To load World Cup 2018 data from API, open and edit components/HomeScreen.js then add constructor function before rendering function.

constructor(props){
  super(props);
  this.state ={ isLoading: true}
}

Add function for load API JSON data which the JSON response set to the dataSource.

componentDidMount(){
  return fetch('https://raw.githubusercontent.com/openfootball/world-cup.json/master/2018/worldcup.json')
    .then((response) => response.json())
    .then((responseJson) => {
      // console.log(responseJson);
      this.setState({
        isLoading: false,
        dataSource: responseJson.rounds,
      }, function(){

      });

    })
    .catch((error) =>{
      console.error(error);
    });
}

The response from API holds by dataSource variable that will use in the view in the next step.

Display List of World Cup Matchdays

We will use the List and ListItem component of React Native Elements (react-native-elements) module. First, install react-native-elements using this command.

yarn add react-native-elements

Open and edit again components/HomeScreen.js then replace all imports with these imports of React, Component (react), StyleSheet, ScrollView, ActivityIndicator, Text, View (react-native), List, and ListItem (react-native-elements).

import React, { Component } from 'react';
import { StyleSheet, ScrollView, ActivityIndicator, Text, View  } from 'react-native';
import { List, ListItem } from 'react-native-elements';

Next, replace all render function with this React Native rendered template which the ActivityIndicator load only if the state status is loading. The list that gets from the data source displaying to the ListItem after mapping the array of the data source.

render() {
  if(this.state.isLoading){
    return(
      <View style={styles.activity}>
        <ActivityIndicator/>
      </View>
    )
  }

  return(
    <ScrollView style={styles.container}>
      <List>
        {
          this.state.dataSource.map((item, i) => (
            <ListItem
              key={i}
              title={item.name}
              leftIcon={{name: 'soccer-ball-o', type: 'font-awesome'}}
              onPress={() => {
                this.props.navigation.navigate('Details', {
                  matches: `${JSON.stringify(item.matches)}`,
                });
              }}
            />
          ))
        }
      </List>
    </ScrollView>
  );
}

Add style const before the export code.

const styles = StyleSheet.create({
  container: {
   flex: 1,
   paddingBottom: 22
  },
  item: {
    padding: 10,
    fontSize: 18,
    height: 44,
  },
  activity: {
    flex: 1,
    padding: 20,
  }
})
Display World Cup 2018 Matchdays Details

We will display World Cup 2018 Matchdays Details in the DetailsScreen. Open and edit components/DetailsScreen.js then replace all imports with this.

import React, { Component } from 'react';
import { StyleSheet, ScrollView, View } from 'react-native';
import { List, ListItem, Text, Card } from 'react-native-elements';

Next, replace all render function with these lines codes.

render() {
  const { navigation } = this.props;
  const matches = JSON.parse(navigation.getParam('matches', 'No matches found'));
  console.log(matches);

  return (
    <ScrollView>
      <Card style={styles.container}>
        {
          matches.map((item, key) => (
            <View key={key} style={styles.subContainer}>
              if(item.group) {
                <View>
                  <Text h3>{item.group}</Text>
                </View>
              }
              <View>
                <Text h3>{item.team1.name} vs {item.team2.name}</Text>
              </View>
              <View>
                <Text h5>{item.date}</Text>
              </View>
              <View>
                <Text h4>{item.score1} - {item.score2}</Text>
              </View>
              if(item.goals1.length > 0) {
                item.goals1.map((item2, key2) => (
                  <View key={key2}>
                    <Text h4>{item2.name} ({item2.minute})</Text>
                  </View>
                ))
              }
              if(item.goals2.length > 0) {
                item.goals2.map((item3, key3) => (
                  <View key={key3}>
                    <Text h5>{item3.name} ({item3.minute})</Text>
                  </View>
                ))
              }
            </View>
          ))
        }
      </Card>
    </ScrollView>
  );
}

Add StyleSheet const before the export code.

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20
  },
  subContainer: {
    flex: 1,
    paddingBottom: 20,
    borderBottomWidth: 2,
    borderBottomColor: '#CCCCCC',
  }
})
Run the React Native World Cup 2018 App

To run the application in Expo App, you can find in step 1 of this article. If there's no error found, you will see the result like this.


Next, to run or build as the Native App, type this command to install React Native CLI first.

sudo npm install -g react-native-cli

Next, eject the project from the Create React Native App by type this command.

npm run eject

You will get questions like below, make it the same with the one that we choose.

? How would you like to eject from create-react-native-app? React Native: I'd like a regular React Native project.
We have a couple of questions to ask you about how you'd like to name your app:
? What should your app appear as on a user's home screen? React World Cup
? What should your Android Studio and Xcode projects be called? ReactWorldCupApp

Next, to run the Native iOS or Android App in the Simulator, type this command.

react-native run-ios
react-native run-android

That it's for now. Any suggestions are open for next React Native tutorial. You can find the full working source code in our GitHub.