How to build a Progressive Blog App with Apollo and Cosmic JS?

How to build a Progressive Blog App with Apollo and Cosmic JS?

Building a Progressive Blog App with Apollo and Cosmic JS. Build a fully functional blog Interface in a half hour with Apollo Graphql client and Cosmic JS ...

Come with me on a short adventure as we build a fast, simple interface for publishing blog style articles. Something sensible. It should look clean and simple yet have the ability to perform powerful resource fetching with some query magic. I’m talking about Graphql, the query language built with web APIs in mind. And speaking of web APIs, we will also be using our handy Content Management Service: Cosmic JS, to Create and Store our Blog Data.

TLDR:

Progressive Apollo Blog

Progressive Apollo Blog Codebase


0.0 Before You Start

Before you go any further make sure you have the required developer tools installed on your machine. Mainly you will need Node JSits accompanying package manager: npm, and git. Git is semi optional and will only be used to code storage and deployment if that is your goal.


Once you have those installed we can begin setting up our project and eventually start writing some Javascript.

0.1 Libraries and packages

Let’s go over the main packages that we will use to create our blog platform.

  • Create React App — We will be leveraging the ever prevalent React library to build our UI components. To bootstrap our project we will also be using a handy command line tool create-reate-app so that we can spend as little time as possible on configuration and setup and just get to creating meaningful javascript.
  • Semantic UI- This is a UI framework that will allow us to import fully styled UI components. No fussing around with tedious CSS specs to get something that looks nice right out of the gate.
  • Apollo / Graphql — These two packages go hand in hand. Apollo will be used as the Graphql client to make requests to our Graphql server endpoints. It’s easy to configure and very straight forward to use. Again, allowing us to focus on writing less javascript and instead focusing on the high level composition of our application. Graphql of course will allow us to make requests that return only data we care about, letting us efficiently grab content from Cosmic JS.

I believe with all that boring business out of the way, we can start slapping our keyboards!

1.0 Setting Up Our Project

Let’s fire up our terminal and start bootstrapping our project source files. For those that don’t have Create React App installed, we can do that with a simple npm command:

$npm install -g create-react-app

Once this finishes (or you have this package already installed), we can summon our initial project files by running the cli:

$create-react-app apollo-blog

You will notice a fair amount of wizardry occurring in your terminal as our app is bootstrapped with all sorts of powerful libraries and source code. Taking a look at our file system will show a directory titled apollo-blog. Changing directories into this folder will show a structure similar to this:

 apollo-blog/
    README.md 
    node_modules/
    package.json
    public/
        index.html
        favicon.ico
    src/
        App.css
        App.js
        App.test.js
        index.css
        index.js
        logo.svg

We should now be able to run:

$npm start

or

$yarn start

This will run the start script stored in our `package.json` file which is all bundled together with Webpack and build tools that will handle compiling all of our React source code and bundling that into files ready to be served to a browser.

After the script runs you should see a simple message in your terminal, and your default browser should open to a tab with project running. You should see something like this:

1.1 Installing Javascript Libraries

The next step is installing some npm libraries so that will help quickly create a good looking App Interface as well as easily fetch data from the Cosmic JS graphql servers.

In your terminal run the following command and let’s talk about what each of these packages will be doing for us:

$npm install --save apollo-boost react-apollo graphql dotenv semantic-ui-css semantic-ui-react react-router-dom

apollo-boost / react-apollo / graphql — These guys are going to serve as the main solution for getting our data efficiently and scalably from Cosmic JS servers to our client side UI. They provide wrappers for our components to be able to configure queries and provide useful variables for data loading and error handling.

dotenv — this package will allow is to configure semi sensitive keys so we don’t have to store anything publicly for accessing our Cosmic JS Bucket.

semantic-ui-css / semantic-ui-react — Our UI framework that will let us import pre-styled containers and components letting us focus on programming functionality, spending less time fidgeting with CSS and other styling considerations.

react-router-dom — A react library that will allow us to configure url routing logic to control linking within our app and accessing URL parameters.

with these installed we can begin writing some javascript!

1.2 Configuring Environment Variables

We are going to add a minimal security precaution so that we won’t let just any request come through our bucket’s API endpoint, feel free to skip this section but be warned that your components will behave a little differently and your bucket can be queried from anyone with the knowhow to make API Requests. So, you know… don’t put any sensitive info in your buckets.


We are going to require a read_key to be attached to every API request to our bucket. You’ll have to generate one by heading to the settings tab for your Cosmic JS bucket and clicking on Basic Settings. Cosmic JS Your Bucket settings > main.

At the top there should be as section titled API Access API Read Access Key. Click on the button to Generate new key. Copy the key to your clipboard and let’s configure our project directory with our config file:

$touch .env

this file is going to be used to configure our project with our API Read Access Key so we don’t have to hard code it in with our source code and commit it for the world / other prying eyes to see.

simply add one line to your .env file:

REACT_APP_COSMIC_JS_READ_KEY=your_cosmic_js_read_key

Make sure you prefix your variable name with REACT_APP! The build scripts that bundle our source code will look for this to make variables available in our compiled javascript. With that done, we are now ready to use this key in our React project.

2.0 Creating our Routes and Components

Finally, we are ready to create our Components and set up our routes. In an effort to keep things as simple as possible we are just creating two routes and two main components:

Routes

{protocol}://{host}/
  • The home route that will list our article.
{protocol}://{host}/article/:articleName
  • The article route that will display our article content.

Components

/views/home.js
  • This component will fetch all articles and display general article info.
/views/article.js
  • The component that will fetch a single article and display all article content.

2.1 Configuring App.js

Let’s go ahead and open the App.js component in whatever text editor you prefer, and start to configure it with our routing logic and our Graphql client.

We are going to import one component wrapper from react-apollo and one constructor function that will let the components within our component wrapper make requests to a specified Graphql server ( for us this will be the Cosmic JS’s Graphql server).

We also want to import our wrapping components for react-router-dom. This will allow us to us our browser url to systematically switch component views and access any url parameters.

Lastly we are going to import a CSS file from Semantic UI so that we can leverage it’s class selectors and give imported components their base stylings.

Here’s what our App.js should look like after everything is properly configured:

import React, { Component } from 'react'
	import ApolloClient from 'apollo-boost'
	import { ApolloProvider } from 'react-apollo'
	import { BrowserRouter, Route } from 'react-router-dom'
	import './App.css'
	import 'semantic-ui-css/semantic.min.css'
import Home from './views/home'
import Article from './views/article'


// creates our Graphql client using the CosmicJS Graphql endpoint
const client = new ApolloClient({
  uri: "https://graphql.cosmicjs.com/v1"
})


class App extends Component {
  render() {
    return (
      <ApolloProvider client={client}>
        <BrowserRouter>
          <div className="router-container">
            <Route exact path="/" component={Home} />
            <Route path="/article/:articleName" component={Article} />
          </div>
        </BrowserRouter>
      </ApolloProvider>
    )
  }
}


export default App

2.2 Creating The Home View

Let’s create a new file in a new directory


src/views/home.js

This folder will store all of our view layer React Components. Our Home View will just return some brief info about our site and a list of articles that have been published to our blog.

The main parts of this component are a heading that display a title and a site description, and a list that will display Semantic UI components.

We also will need to configure this view with some Graphql logic so that it can make requests to Cosmic JS

import React from 'react'
import gql from 'graphql-tag'
import { graphql } from 'react-apollo'
import { Link } from 'react-router-dom'

// Component from Semantic UI
import { Container, Image, Card, Label, Loader } from 'semantic-ui-react'


const GET_ARTICLES = gql`
  query Articles($read_key: String!) {
    objectsByType(bucket_slug: "apollo-blog", type_slug: "articles", read_key: $read_key ) {
      _id
      slug
      created_at 
      title
      type_slug
      metadata
    }
  }
`


class Home extends React.Component {
  render() {
    const { data: { loading, error, objectsByType } } = this.props
    const styles = {
      heading: {
        margin: '0 0 20px 0',
        height: '300px',
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center',
        fontFamily: "'Rubik', sans-serif",
        backgroundColor: '#4ABDAC',
        color: 'white',
      },
      headingTitle: {
        marginBottom: '30px',
        display: 'flex',
        flexDirection: 'row',
        justifyContent: 'center',
        alignItems: 'center',
      },
      container: {
        minHeight: 'calc(100vh - 500px)',
        display: 'flex',
        flexDirection: 'row',
        justifyContent: 'center',
        alignItems: 'flex-start',
        flexWrap: 'wrap',
      },
      title: {
        fontSize: '200%',
        margin: '10px 0',
      },
      card: {
        minWidth: '350px',
      },
      summary: {
        fontSize: '120%',
        lineHeight: '25px',
      }
    }


    return (
      <Container className="home-container" style={styles.container}>
        <div className="home-heading" style={styles.heading}>
          <div style={styles.headingTitle}>
            <h1>Apollo Blog</h1>
            <p>A simple and extensible blog platform</p>
          </div>
        </div>
        {loading ? <Loader active inline="centered" size="massive">...loading</Loader> : null}
        {error ? `Error! ${error.message}` : null}
        {objectsByType
          ? <Container className="articleList-container" style={styles.container}>
            {objectsByType.map(article => {
              let { summary, image, categories, author } = article.metadata
              if (categories) categories = categories.split(' ')


              return (
                <Link key={article._id} to={`/article/${article.slug}`}>
                  <Card style={styles.card}>
                    <Card.Content>
                      {image ? <Image src={image.url} /> : null}
                      <Card.Header style={styles.title}>{article.title}</Card.Header>
                      <Card.Meta>
                        {author ? author.name : null}
                        <span className='date'>{article.created_at}</span>
                      </Card.Meta>
                      <Card.Description style={styles.summary}>{summary}</Card.Description>
                    </Card.Content>
                    {categories
                      ? <Card.Content extra>
                        {categories.map(category => <Label key={category}>{category.replace(/,/g, '')}</Label>)}
                      </Card.Content>
                      : null
                    }
                  </Card>
                </Link>
              )
            })}
          </Container>
          : null
        }
      </Container>
    )
  }
}


export default graphql(GET_ARTICLES, {
  options: {
    variables: {
      read_key: process.env.REACT_APP_COSMIC_JS_READ_KEY,
    }
  },
  props: ({ data }) => ({
    data,
  }),
})(Home)

Now we have ye old React Component, that will fetch articles from our content manager (Cosmic JS) before the component renders and pass those as an array on component props.

Apollo also gives us some handy properties from is data object, specifically an error object, and a loading boolean, which we use to conditionally render components, such as loading message when the request is fetching, and an error message when our error object returns a message.

2.3 Creating The Article View

With our list of articles displaying on our home page, we need to Create the view that will display the blog content contained in each article object.

Let’s create another file in our views directory:

src/views/article.js

Creating this component is similar to the Home View, but our query is going to include an article identifier from our URL stored on a prop: match which react-router-dom creates for us when we render a component at a Route.

import React from 'react'
import { Link } from 'react-router-dom'
import gql from 'graphql-tag'
import { Query } from 'react-apollo'
import { Container, Loader, Label, Image } from 'semantic-ui-react'
import './_article.css'

const GET_ARTICLE_BY_SLUG = gql`
  query Article($read_key: String!, $slug: String!) {
    object(bucket_slug: "apollo-blog", read_key: $read_key, slug: $slug ) {
      _id
      created_at
      title
      content
      metadata
    }
  }
`




const Article = ({ match }) => {
  const read_key = process.env.REACT_APP_COSMIC_JS_READ_KEY
  const article_slug = match.params.articleName


  const styles = {
    container: {
      display: 'flex',
      flexDirection: 'row',
      justifyContent: 'center',
      alignItems: 'flex-start',
    },
    articleContainer: {
      width: '95%',
      maxWidth: '1000px',
      margin: '20px auto',
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'flex-start',
      alignItems: 'center',
    },
    article: {
      width: '70%',
      margin: '-20px 0 0 20px',
      fontFamily: '"Quicksand", sans-serif',
    },
    heading: {
      height: '100px',
      width: '100%',
      display: 'flex',
      flexDirection: 'row',
      justifyContent: 'center',
      alignItems: 'center',
      backgroundColor: '#4ABDAC',
    },
    headingTitle: {
      color: 'white',
    },
    details: {
      width: '100%',
      minHeight: '200px',
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'center',
      alignItems: 'center'
    },
    lineOne: {
      width: '95%',
      maxWidth: '900px',
      display: 'flex',
      flexDirection: 'row',
      justifyContent: 'flex-start',
    },
    title: {
      width: '50%',
      fontSize: '250%',
      textAlign: 'right',
      margin: 'auto 20px',
      lineHeight: '35px',
    },
    date: {
      fontSize: '130%',
      lineHeight: '20px',
    },
    image: {
      maxWidth: '950px',
      maxHeight: '500px',
    },
  }




  return (
    <Query query={GET_ARTICLE_BY_SLUG} variables={{ read_key, slug: article_slug }}>
      {({ loading, error, data }) => {
        if (loading) return <Loader active inline="centered" size="massive">...loading</Loader>
        if (error) return `Error! ${error.message}`
        let { image, author, categories } = data.object.metadata
        if (categories) categories = categories.split(' ')
        return (
          <Container>
            <div className="post-heading" style={styles.heading}>
              <Link to="/" className="header-btn">
                <h2>Apollo Blog</h2>
              </Link>
            </div>
            <div className="post-details" style={styles.details}>
              <div style={styles.lineOne}>
                <h4 className="post-title" style={styles.title}>{data.object.title}</h4>
                <h6 className="post-date" style={styles.date}>{data.object.created_at}</h6>
              </div>
              {categories
                ? <div> {categories.map(category => <Label key={category}>{category.replace(/,/g, '')}</Label>)} </div>
                : null
              }
              {image ? <Image src={image.url} style={styles.image} /> : null}
            </div>
            <div style={styles.articleContainer}>
              {author ? <h3>By {author.title}</h3> : null}
              <div
                className="article"
                dangerouslySetInnerHTML={{ __html: data.object.content }}
                style={styles.article}
              />
            </div>
          </Container>
        )
      }}
    </Query>
  )
}


export default Article

This component is much simpler than our Home component, mostly due to the fact that we are just using the Query component wrapper instead of turning our component into a higher level component using the Graphqlcomponent. This gives us access to our Graphql directly in our component logic but does not make it available on component props! So take note.

For both components I have included some minimal styling objects in the source code, but feel free to use your creativity and change up the styling properties to create your own look and feel.

And that’s it! We have built two relatively simple and scalable React components that are configured to two separate url routes. We can control our views easily with react-router-dom and fetch our data sensibly with the power of Apollo / Graphql and Cosmic JS.

3.0 Deployment

create-react-app comes bundled with some handy deployment scripts if you feel so inclined to make your application available to the world.


3.1 Running the Build Script

If you take a look at the package.json file that we have a script called build. Running this will compile all your project files and bundle them into a static build directory that is ready to deploy to any hosting service.


You’ll also notice after the script finishes that you have an option to publish directly to github pages using the serve module. You just need to add a homepage value in package.json and make sure the serve package is installed with either npm or yarn.

Follow the link at the end of the build message to learn more about deployment using this method.

3.2 Deploying Using Netlify and Github

Netlify provides app building and deployment services and they will give you a free ( if not a little bit verbose ) URL for you to deploy client side code. The process is pretty easy and we can use a github repository to deploy our code continuously when we make changes to our source code.


After you create and account / Log in to the Netlify dashboard, there should be a tab called sites.

Clicking the sites tab will reveal a list of sites you have deployed on Netlify. From here you have two options:

  1. Deploy using your static build directory created using the build script.
  2. Connect your Netlify account to a git repository and use continuous deployment. This step requires that you commit your code to a git repository.

Deploying the static build directory is super simple but will require you to manually build and upload files to Netlify. Simply drag the build directory directly over the area at the bottom of the sites tab from the Netlify Dashboard.

This will automatically deploy your site to a url that Netlify will generate. Simple but requires work every time you update your source code.

On the far right side there will be a button that reads New site from Git.Selecting this option will walk you through the process of authorizing Netlify to access a code repository. After these steps are finished Netlify will build your site files from a build script you specify and deploy it automatically each time you make a commit to your repo!

Conclusion

Well that’s it for me today. Happy hacking until we meet again :)

Originally published on https://hackernoon.com

Learn how to use the React Native Navigation Library

Learn how to use the React Native Navigation Library

In this tutorial, you'll learn how to use the React Native Navigation library. Learn how to set up React Native Navigation and use the stack and tab navigation. Learn how to load icons from React Native Vector Icons instead of using image icons.

One of the most important aspects of React Native app development is the navigation. It’s what allows users to get to the pages they’re looking for. That’s why it’s important to choose the best navigation library to suit your needs.

If your app has a lot of screens with relatively complex UI, it might be worth exploring React Native Navigation instead of React Navigation. This is because there will always be performance bottlenecks with React Navigation, since it works off the same JavaScript thread as the rest of the app. The more complex your UI, the more data has to be passed to that bridge, which can potentially slow it down.

In this tutorial, we’ll be looking at the React Native Navigation library by Wix, an alternative navigation library for those who are looking for a smoother navigation performance for their React Native apps.

Prerequisites

Knowledge of React and React Native is required to follow this tutorial. Prior experience with a navigation library such as React Navigation is optional.

App Overview

In order to demonstrate how to use the library, we’ll be creating a simple app that uses it. The app will have five screens in total:

  • Initialization: this serves as the initial screen for the app. If the user is logged in, it will automatically navigate to the home screen. If not, the user is navigated to the login screen.
  • Login: this allows the user to log in so they can view the home, gallery, and feed. To simplify things, the login will just be mocked; no actual authentication code will be involved. From this screen, the user can also go to the forgot-password screen.
  • ForgotPassword: a filler screen, which asks for the user’s email address. This will simply be used to demonstrate stack navigation.
  • Home: the initial screen that the user will see when they log in. From here, they can also navigate to either the gallery or feed screens via a bottom tab navigation.
  • Gallery: a filler screen which shows a photo gallery UI.
  • Feed: a filler screen which shows a news feed UI.

Here’s what the app will look like:

You can find the source code of the sample app on this GitHub repo.

Bootstrapping the App

Let’s start by generating a new React Native project:

react-native init RNNavigation --version [email protected]

Note: we’re using a slightly older version of React Native, because React Native Navigation doesn’t work well with later versions of React Native. React Native Navigation hasn’t really kept up with the changes in the core of React Native since version 0.58. The only version known to work flawlessly with React Native is the version we’re going to use. If you check the issues on their repo, you’ll see various issues on version 0.58 and 0.59. There might be workarounds on those two versions, but the safest bet is still version 0.57.

As for React Native version 0.60, the core team has made a lot of changes. One of them is the migration to AndroidX, which aims to make it clearer which packages are bundled with the Android operating system. This essentially means that if a native module uses any of the old packages that got migrated to the new androidx.* package hierarchy, it will break. There are tools such as jetifier, which allows for migration to AndroidX. But this doesn’t ensure React Native Navigation will work.

Next, install the dependencies of the app:

  • react-native-navigation — the navigation library that we’re going to use.
  • @react-native-community/async-storage — for saving data to the app’s local storage.
  • react-native-vector-icons — for showing icons for the bottom tab navigation.
yarn add react-native-navigation @react-native-community/async-storage react-native-vector-icons

In the next few sections, we’ll be setting up the packages we just installed.

Setting up React Native Navigation

First, we’ll set up the React Native Navigation library. The instructions that we’ll be covering here are also in the official documentation. Unfortunately, it’s not written in a very friendly way for beginners, so we’ll be covering it in more detail.

Note: the demo project includes an Android and iOS folders as well. You can use those as a reference if you encounter any issues with setting things up.

Since the name of the library is very long, I’ll simply refer to it as RNN from now on.

Android Setup

In this section, we’ll take a look at how you can set up RNN for Android. Before you proceed, it’s important to update all the SDK packages to the latest versions. You can do that via the Android SDK Manager.

settings.gradle

Add the following to your android/settings.gradle file:

include ':react-native-navigation'
project(':react-native-navigation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-navigation/lib/android/app/')

Gradle Wrapper Properties

In your android/gradle/wrapper/gradle-wrapper.properties, update Gradle’s distributionUrl to use version 4.4 if it’s not already using it:

distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

build.gradle

Next, in your android/build.gradle file, add mavenLocal() and mavenCentral() under buildscript -> repositories:

buildscript {
    repositories {
      google()
      jcenter()

      // add these:
      mavenLocal()
      mavenCentral()
    }
}

Next, update the classpath under the buildscript -> dependencies to point out to the Gradle version that we need:

buildscript {
  repositories {
    ...
  }

  dependencies {
    classpath 'com.android.tools.build:gradle:3.0.1'
  }

}

Under allprojects -> repositories, add mavenCentral() and JitPack. This allows us to pull the data from React Native Navigation’s JitPack repository:

allprojects {
allprojects {

  repositories {
    mavenLocal()
    google()
    jcenter()
    mavenCentral() // add this
    maven { url 'https://jitpack.io' } // add this
  }

}

Next, add the global config for setting the build tools and SDK versions for Android:

allprojects {
  ...
}

ext {
    buildToolsVersion = "27.0.3"
    minSdkVersion = 19
    compileSdkVersion = 26
    targetSdkVersion = 26
    supportLibVersion = "26.1.0"
}

Lastly, we’d still want to keep the default react-native run-android command when compiling the app, so we have to set Gradle to ignore other flavors of React Native Navigation except the one we’re currently using (reactNative57_5). Ignoring them ensures that we only compile the specific version we’re depending on:

ext {
 ...
}

subprojects { subproject ->
    afterEvaluate {
        if ((subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) {
            android {
                variantFilter { variant ->
                    def names = variant.flavors*.name
                    if (names.contains("reactNative51") || names.contains("reactNative55") || names.contains("reactNative56") || names.contains("reactNative57")) {
                        setIgnore(true)
                    }
                }
            }
        }
    }
}

Note: there are four other flavors of RNN that currently exist. These are the ones we’re ignoring above:

  • reactNative51
  • reactNative55
  • reactNative56
  • reactNative57

android/app/build.gradle

On your android/app/build.gradle file, under android -> compileOptions, make sure that the source and target compatibility version is 1.8:

android {
  defaultConfig {
    ...
  }

  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

Then, in your dependencies, include react-native-navigation as a dependency:

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
    implementation "com.facebook.react:react-native:+"
    implementation project(':react-native-navigation') // add this
}

Lastly, under android -> defaultConfig, set the missingDimensionStrategy to reactNative57_5. This is the version of RNN that’s compatible with React Native 0.57.8:

defaultConfig {
  applicationId "com.rnnavigation"
  minSdkVersion rootProject.ext.minSdkVersion
  targetSdkVersion rootProject.ext.targetSdkVersion
  missingDimensionStrategy "RNN.reactNativeVersion", "reactNative57_5" // add this
  versionCode 1
  versionName "1.0"
  ndk {
    abiFilters "armeabi-v7a", "x86"
  }
}

MainActivity.java

On your app/src/main/java/com/rnnavigation/MainActivity.java file, extend from RNN’s NavigationActivity instead:

package com.rnnavigation;

// import com.facebook.react.ReactActivity;
import com.reactnativenavigation.NavigationActivity;

// public class MainActivity extends ReactActivity {
public class MainActivity extends NavigationActivity {
  // remove all code inside
}

Since we’ve removed the default code that React Native uses, we’ll no longer need to register the main component as you’ll see later in the Building the App section:

// index.js
import { AppRegistry } from "react-native";
import App from "./App";
import { name as appName } from "./app.json";

AppRegistry.registerComponent(appName, () => App);

MainApplication.java

Next, you also need to update the app/src/main/java/com/rnnavigation/MainApplication.java file to inherit from RNN’s class instead. Start by importing RNN’s classes:

import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;

// add these
import com.reactnativenavigation.NavigationApplication;
import com.reactnativenavigation.react.NavigationReactNativeHost;
import com.reactnativenavigation.react.ReactGateway;

Next, inherit from RNN’s NavigationApplication class instead:

// public class MainApplication extends Application implements ReactApplication {
public class MainApplication extends NavigationApplication {

}

Lastly, completely replace the contents of the class with the following:

@Override
protected ReactGateway createReactGateway() {
  ReactNativeHost host = new NavigationReactNativeHost(this, isDebug(), createAdditionalReactPackages()) {
    @Override
    protected String getJSMainModuleName() {
      return "index";
    }
  };
  return new ReactGateway(this, isDebug(), host);
}

@Override
public boolean isDebug() {
  return BuildConfig.DEBUG;
}

protected List<ReactPackage> getPackages() {
  return Arrays.<ReactPackage>asList(

  );
}

@Override
public List<ReactPackage> createAdditionalReactPackages() {
  return getPackages();
}

The only thing that might look familiar to you in the above code is the getPackages() method. Just like in the standard React Native project, this is where you can initialize the classes of your native dependencies.

iOS Setup

In this section, we’ll set up RNN for iOS. Before you proceed, it’s important that you have updated Xcode to the latest available version. This helps to avoid potential errors that comes with outdated Xcode modules.

First, open the ios/RNNavigation.xcodeproj file with Xcode. This is the corresponding Xcode project for the app.

Once opened, in your project navigator (left pane where the project files are listed), right-click on Libraries -> Add files to RNNavigation. On the file picker that shows up, go to the node_modules/react-native-navigation/lib/ios directory and select the ReactNativeNavigation.xcodeproj file:

Next, click on RNNavigation in the TARGETS row and click on the Build Phases tab. From there, look for Link Binary With Libraries, expand it, then click on the button for adding a new item:

On the modal window that pops up, search for the libReactNativeNavigation.a file, select it, and then click on the Add button:

Next, open the AppDelegate.m file and replace its contents with the following. This is basically the entry point of the React Native app (similar to the MainApplication.java in Android). We’re updating it so that it uses RNN instead:

#import "AppDelegate.h"

 #import <React/RCTBundleURLProvider.h>
 #import <React/RCTRootView.h>
 #import <ReactNativeNavigation/ReactNativeNavigation.h>

 @implementation AppDelegate

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
     NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
     [ReactNativeNavigation bootstrap:jsCodeLocation launchOptions:launchOptions];

     return YES;
 }

 @end

That’s pretty much it for the linking of RNN to iOS. But if you encounter any issues, you’ll probably have to follow the next section as well.

Common Issues

In this section, we’ll go through some of the most common issues that you may encounter when linking RNN to iOS.

When you’ve edited and saved the AppDelegate.m file, you’ll probably encounter this issue. This will appear in red squiggly lines in the file itself:

! 'RCTBundleURLProvider.h' file not found

This happens because the React scheme is missing from your project.

To make it available, execute the following commands inside your project’s root directory (RNNavigation):

npm install -g react-native-git-upgrade
react-native-git-upgrade

This will add the missing files to your project.

Once that’s done, go to Product -> Scheme -> Manage Schemes, then click on the + button to add a new scheme. From the Target dropdown, select React, then click OK to add it:

Once added, make sure both the Show and Shared checkboxes are checked:

The next issue that you might encounter is this:

'ReactNativeNavigation/ReactNativeNavigation.h' file not found.

This means it couldn’t find the said file in your project’s path. To solve it, click on RNNavigation in the TARGETS. Then click on Build Settings and below it, make sure the All and Combined is used as a filter, then look for header search in the search bar. Double-click on Header Search Paths, click on the + button, and add $(SRCROOT)/../node_modules/react-native-navigation/lib/ios as a path:

Setting up AsyncStorage and Vector Icons

The process of setting up AsyncStorage and Vector Icons is very similar to the install processes outlined above, so I’ll just link to the official documentation.

Here are the instructions for AsyncStorage:

  • Android Setup.
  • iOS Setup. Be sure to follow the non-pods version, as that’s easier to get set up with. The non-pods (short for non CocoaPods) is one that doesn’t use CocoaPods as a dependency manager. The main file of the native module will simply be linked as a library. That’s basically the same thing we did with the libReactNativeNavigation.a file earlier.

And here are the instructions for Vector Icons. To simplify things, just follow the instructions for adding the whole Fonts folder to the Xcode project:

Note: you can always check the GitHub repo if you get lost.

Okay, so that was a lot of manual setup. If you really need RNN in your project, then it’s a necessity. Every time you introduce a new dependency that has a native link, you have to follow the instructions for manually linking it. react-native link won’t work, because we’ve replaced ReactApplication with NavigationApplication in MainApplication.java, so the linking is now done a little bit differently. You can probably get away with still running react-native link if you know exactly what it’s doing and you can completely undo what it’s done. But it’s safer to just follow the manual linking instructions.

Building the App

Now we’re ready to finally start building the app.

index.js

First, open the existing index.js on the root of the project directory and replace its contents with the following. This serves as the entry point of the app. If you noticed, we no longer have to register the main app component using React Native’s AppRegistry. Instead, we’re now using RNN’s registerComponent() method. This has to do with the updates we did earlier to the MainActivity.java and AppDelegate.m file.

The registerComponent() method accepts the screen’s unique name and the component to use to render the screen. Once it’s registered, we call the registerAppLaunchedListener() method to set the root screen for the app to LoadingScreen. This is similar to what the AppRegistry.registerComponent() does:

// index.js
import { Navigation } from "react-native-navigation";
import Icon from "react-native-vector-icons/FontAwesome";

import Loading from "./src/screens/Loading"; // the loading screen

import "./loadIcons"; // file for loading the icons to be used in the bottom tab navigation

Navigation.registerComponent(`LoadingScreen`, () => Loading);

Navigation.events().registerAppLaunchedListener(() => {
  // set the root component
  Navigation.setRoot({
    root: {
      component: {
        name: "LoadingScreen"
      }
    }
  });
});

Loading Screen

The loading screen serves as the entry point of the app. But you may be asking why a loading screen? Why not a login screen instead? This is because our sample app has a mock login system, meaning that we first have to determine if a user is already logged in or not. Using a loading screen works better than having to initially load a login screen only to find out that a user is already logged in, so we then have to navigate them to the home screen.

Start by creating a src/screens/Loading.js file and add the following:

// src/screens/Loading.js
import React, { Component } from "react";
import { View, Text, ActivityIndicator, StyleSheet } from "react-native";

import { goToLogin, goToTabs } from "../../navigation"; // import the functions for loading either the login screen or the tabs screen (shows home screen by default)

import AsyncStorage from "@react-native-community/async-storage";

Next, create the component itself. When the component is mounted, we try to get the username of the logged-in user from local storage. If it exists, then we navigate the user to the tabs, otherwise to the login screen:

export default class Loading extends Component {
  async componentDidMount() {
    const username = await AsyncStorage.getItem("username");
    if (username) {
      goToTabs(global.icons, username);
    } else {
      goToLogin();
    }
  }

  render() {
    // show loading indicator
    return (
      <View style={styles.container}>
        <ActivityIndicator size="large" color="#0000ff" />
      </View>
    );
  }
}
//

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center"
  }
});

In the above code, notice we’re passing global.icons as an argument to the goToTabs() function. That value is being set in the loadIcons.js that we imported from the index.js file earlier. Its job is to load the icons to be used for the bottom tabs, as you’ll see later.

navigation.js

This is where we register all the screens of the app and declare our navigation functions for navigating between the login screen and the tabbed screens:

// navigation.js
import { Navigation } from "react-native-navigation";

import Login from "./src/screens/Login";
import ForgotPassword from "./src/screens/ForgotPassword";
import Home from "./src/screens/Home";
import Feed from "./src/screens/Feed";
import Gallery from "./src/screens/Gallery";

Navigation.registerComponent(`LoginScreen`, () => Login);
Navigation.registerComponent(`ForgotPasswordScreen`, () => ForgotPassword);
Navigation.registerComponent(`HomeScreen`, () => Home);
Navigation.registerComponent(`FeedScreen`, () => Feed);
Navigation.registerComponent(`GalleryScreen`, () => Gallery);

The goToLogin() function creates a stack navigation. In RNN, these navigation types are called “Layouts”. Currently, there are only three: stacks, tabs, and drawers. We’ll only use stack and tabs in this tutorial, but here’s a brief overview of each one:

  • Stack: each new screen you navigate to is laid out on top of the current one. So when you go back to the previous screen, the idea is to simply “pop” the current screen out of the stack. We’ll be using the stack navigation to navigate between the Login screen and ForgotPassword screen.
  • Tab: each screen can be accessed via a bottom tab navigation. Each tab has both icon and text on it to describe the screen it navigates the user to. This type of navigation is commonly used if there are two or more main screens within the app. Having a bottom tab navigation allows for easy access between those screens. We’ll be using the tab navigation to navigate between the Home, Gallery, and Feed screens.
  • Drawer: also called the side menu. This is called drawer because it’s commonly hidden within a hamburger icon and it only shows the menu under it when clicked on.

Going back to the code, we’ve only added the Login screen as a child of stack navigation, even though the ForgotPassword screen is part of it as well. As mentioned earlier, we’ll be using stack navigation to navigate between the Login screen and the ForgotPassword screen. Yet we’ve only added the Login screen here as a child. Adding it will simply make it as the default screen for the stack. In a stack navigation, you should only add the initial screen for that specific stack as the child, as you’ll see later.

The minimum requirement for a child is to add the name property for each screen. This is the name of the screen to be used for rendering. This should be the same name you used when you registered the component:

export const goToLogin = () =>
  Navigation.setRoot({
    root: {
      stack: {
        // create a stack navigation
        id: "stackMain",
        children: [
          {
            component: {
              name: "LoginScreen"
            }
          }
        ]
      }
    }
  });

Note: supplying an ID for the navigation isn’t required, but it’s good practice—especially if you know that you’ll start using the same layout type multiple times in your app.

Next, add the goToTabs() function. Unlike the previous function, this accepts two arguments: icons and username. icons is the array of icons to be used for the individual tabs, while username is the username of the user who logged in. This time, we’re using the bottomTabs navigation. As the name suggests, this allows the user to navigate between screens using bottom tabs. You can create bottom tabs using the following format:

const iconColor = "#444";
const selectedIconColor = "#0089da";

export const goToTabs = (icons, username) => {
  Navigation.setRoot({
    root: {
      bottomTabs: {
        // create a bottom tabs navigation

        id: "bottomTabsMain",
        children: [
          {
            component: {
              name: "HomeScreen",
              options: {
                bottomTab: {
                  fontSize: 11,
                  text: "Home",
                  icon: icons[0],
                  iconColor,
                  selectedIconColor
                }
              },

              // pass the username as a navigation prop to the Home screen
              passProps: {
                username
              }
            }
          },

          {
            component: {
              name: "GalleryScreen",
              options: {
                bottomTab: {
                  fontSize: 11,
                  text: "Gallery",
                  icon: icons[1],
                  iconColor,
                  selectedIconColor
                }
              }
            }
          },

          {
            component: {
              name: "FeedScreen",
              options: {
                bottomTab: {
                  fontSize: 11,
                  text: "Feed",
                  icon: icons[2],
                  iconColor,
                  selectedIconColor
                }
              }
            }
          }
        ]
      }
    }
  });
};

As you’ve seen from the code above, this pretty much uses the same format as the stack navigation. The only difference is that, this time, we’re also specifying an options property for the individual bottomTab. These options are mostly used for configuring the styles of the individual tab. They’re self-explanatory, so I won’t go into detail, but I just want to explain the icon property. By default, this accepts a local image that’s required by a require('./path/to/image.png') call. But since we’ve already installed Vector Icons, we might as well use it as the icon source instead. The only problem is that we can’t really supply a React component as the value for the icon because it expects a resource. The icons parameter accepts an array of icon resource and that’s what we’re using instead. You’ll learn how we’re loading those in the next section.

Note: you can find more styling options for bottom tabs in the official documentation for Styling. Just look for bottomTabs or bottomTab.

loadIcons.js

Here’s the code for the loadIcons file that we imported in the index.js file earlier. This uses icons from FontAwesome. Here, we’re using the getImageSource() method from Vector Icons to get the actual image resource. This allows us to use it as an icon for the bottom tabs:

// loadIcons.js
import Icon from "react-native-vector-icons/FontAwesome";

(function() {
  Promise.all([
    Icon.getImageSource("home", 11), // name of icon, size
    Icon.getImageSource("image", 11),
    Icon.getImageSource("rss-square", 11)
  ]).then(async values => {
    global.icons = values; // make it available globally so we don't need to load it again
  });
})();

Login Screen

The Login screen is the default screen that the user will see if they aren’t logged in. From here, they can log in by entering their username or they can click on forgot password to view the screen for resetting their password. As mentioned earlier, all of this is just mocked and no actual authentication code is used:

// src/screens/Login.js
import React, { Component } from "react";
import { Navigation } from "react-native-navigation";
import {
  View,
  Text,
  TextInput,
  Button,
  TouchableOpacity,
  StyleSheet
} from "react-native";
import AsyncStorage from "@react-native-community/async-storage";

import { goToTabs } from "../../navigation";

export default class Login extends Component {
  static get options() {
    return {
      topBar: {
        visible: false // need to set this because screens in a stack navigation have a header by default
      }
    };
  }

  state = {
    username: ""
  };

  render() {
    return (
      <View style={styles.wrapper}>
        <View style={styles.container}>
          <View style={styles.main}>
            <View style={styles.fieldContainer}>
              <Text style={styles.label}>Enter your username</Text>
              <TextInput
                onChangeText={username => this.setState({ username })}
                style={styles.textInput}
              />
            </View>

            <Button title="Login" color="#0064e1" onPress={this.login} />

            <TouchableOpacity onPress={this.goToForgotPassword}>
              <View style={styles.center}>
                <Text style={styles.link_text}>Forgot Password</Text>
              </View>
            </TouchableOpacity>
          </View>
        </View>
      </View>
    );
  }

  // next: add login code
}
//

const styles = StyleSheet.create({
  wrapper: {
    flex: 1
  },
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
    padding: 20
  },
  fieldContainer: {
    marginTop: 20
  },
  label: {
    fontSize: 16
  },
  textInput: {
    height: 40,
    marginTop: 5,
    marginBottom: 10,
    borderColor: "#ccc",
    borderWidth: 1,
    backgroundColor: "#eaeaea",
    padding: 5
  }
});

Here’s the login code. This simply stores the username to local storage and navigates the user to the tabbed screens:

login = async () => {
  const { username } = this.state;
  if (username) {
    await AsyncStorage.setItem("username", username);
    goToTabs(global.icons, username);
  }
};

Lastly, here’s the code for navigating to another screen via stack navigation. Simply call the Navigation.push() method and pass in the ID of the current screen as the first argument, and the screen you want to navigate to as the second. The name should be the same one you used when you called Navigation.registerComponent() in the navigation.js file earlier:

goToForgotPassword = () => {
  Navigation.push(this.props.componentId, {
    component: {
      name: "ForgotPasswordScreen"
    }
  });
};

ForgotPassword Screen

As mentioned earlier, this screen is simply used as a filler to demonstrate stack navigation. Make sure that the topBar is set to visible, because it’s where the back button for going back to the Login screen is located:

// src/screens/ForgotPassword.js
import React, { Component } from "react";
import { View, Text, TextInput, Button, StyleSheet } from "react-native";

export default class ForgotPassword extends Component {
  static get options() {
    return {
      topBar: {
        visible: true, // visible
        title: {
          text: "Forgot Password"
        }
      }
    };
  }

  state = {
    email: ""
  };

  render() {
    return (
      <View style={styles.wrapper}>
        <View style={styles.container}>
          <View style={styles.main}>
            <View style={styles.fieldContainer}>
              <Text style={styles.label}>Enter your email</Text>
              <TextInput
                onChangeText={email => this.setState({ email })}
                style={styles.textInput}
              />
            </View>

            <Button
              title="Send Email"
              color="#0064e1"
              onPress={this.sendEmail}
            />
          </View>
        </View>
      </View>
    );
  }

  //
  sendEmail = async () => {};
}
//

const styles = StyleSheet.create({
  wrapper: {
    flex: 1
  },
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
    padding: 20
  },
  fieldContainer: {
    marginTop: 20
  },
  label: {
    fontSize: 16
  },
  textInput: {
    height: 40,
    marginTop: 5,
    marginBottom: 10,
    borderColor: "#ccc",
    borderWidth: 1,
    backgroundColor: "#eaeaea",
    padding: 5
  }
});

You can also have a separate button for going back to the previous screen. All you have to do is call the Navigation.pop() method:

Navigation.pop(this.props.componentId);

Home Screen

The Home screen is the default screen for the tabbed navigation, so it’s what the user will see by default when they log in. This screen shows the user’s name that was passed as a navigation prop as well as a button for logging out. Clicking the logout button will simply delete the username from local storage and navigate the user back to the login screen:

// src/screens/Home.js
import React, { Component } from "react";
import { View, Text, Button, StyleSheet } from "react-native";
import Icon from "react-native-vector-icons/FontAwesome";
import AsyncStorage from "@react-native-community/async-storage";

import { goToLogin } from "../../navigation";

export default class Home extends Component {
  render() {
    const { username } = this.props;
    return (
      <View style={styles.container}>
        <Text style={styles.text}>Hi {username}!</Text>
        <Button onPress={this.logout} title="Logout" color="#841584" />
      </View>
    );
  }
  //

  logout = async () => {
    await AsyncStorage.removeItem("username");
    goToLogin();
  };
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center"
  },
  text: {
    fontSize: 18,
    fontWeight: "bold"
  }
});

In case you’re wondering how we got access to the username, we’ve passed it as a navigation prop from the navigation file earlier:

// navigation.js
{
  component: {
    name: "HomeScreen",
    options: {
      ...
    },

    // here:
    passProps: {
      username
    },

  }
},

Gallery Screen

The Gallery screen is just a filler screen so we won’t be delving too much into it. Basically, it just shows a photo gallery UI:

// src/screens/Gallery.js
import React, { Component } from "react";
import {
  View,
  Text,
  FlatList,
  Image,
  Dimensions,
  StyleSheet
} from "react-native";

const { width } = Dimensions.get("window");
const base_width = width / 2;

const images = [
  {
    id: 1,
    src: require("../images/blake-richard-verdoorn-20063-unsplash.jpg")
  },
  {
    id: 2,
    src: require("../images/casey-horner-487085-unsplash.jpg")
  },
  {
    id: 3,
    src: require("../images/sacha-styles-XK7thML3zEQ-unsplash.jpg")
  },
  {
    id: 4,
    src: require("../images/eberhard-grossgasteiger-1036384-unsplash.jpg")
  },
  {
    id: 5,
    src: require("../images/justin-kauffman-449060-unsplash.jpg")
  },
  {
    id: 6,
    src: require("../images/vincent-guth-182001-unsplash.jpg")
  }
];

export default class Gallery extends Component {
  render() {
    return (
      <View style={styles.container}>
        <FlatList
          data={images}
          keyExtractor={(item, index) => item.id.toString()}
          numColumns={2}
          renderItem={this.renderImage}
        />
      </View>
    );
  }
  //

  renderImage = ({ item }) => {
    return (
      <Image source={item.src} style={{ width: base_width, height: 250 }} />
    );
  };
}

const styles = StyleSheet.create({
  container: {
    flex: 1
  }
});

Feed Screen

Just like the Gallery screen, the Feed screen is also a filler. It simply shows a news feed UI:

// src/screens/Feed.js
import React, { Component } from "react";
import {
  View,
  Text,
  FlatList,
  Image,
  TouchableOpacity,
  StyleSheet
} from "react-native";

const news_items = [
  {
    id: 1,
    title: "The HTML Handbook",
    summary:
      "HTML is the foundation of the marvel called the Web. Discover all you need to know about it in this handy handbook!",
    image: require("../images/amanda-phung-1281331-unsplash.jpg")
  },
  {
    id: 2,
    title: "Angular RxJs In-Depth",
    summary:
      "In this tutorial, we'll learn to use the RxJS 6 library with Angular 6 or Angular 7...",
    image: require("../images/daniil-silantev-318853-unsplash.jpg")
  },
  {
    id: 3,
    title: "How to Create Code Profiles in VS Code",
    summary:
      "This post piggybacks off of the work done by @avanslaars who is a fellow instructor at egghead.io....",
    image: require("../images/vincent-van-zalinge-38358-unsplash.jpg")
  }
];

export default class Feed extends Component {
  render() {
    return (
      <View style={styles.container}>
        <FlatList
          data={news_items}
          keyExtractor={(item, index) => item.id.toString()}
          renderItem={this.renderItem}
        />
      </View>
    );
  }
  //

  renderItem = ({ item }) => {
    return (
      <TouchableOpacity onPress={this.goToNews}>
        <View style={styles.news_item}>
          <View style={styles.news_text}>
            <View style={styles.text_container}>
              <Text style={styles.title}>{item.title}</Text>
              <Text>{item.summary}</Text>
            </View>
          </View>
          <View style={styles.news_photo}>
            <Image source={item.image} style={styles.photo} />
          </View>
        </View>
      </TouchableOpacity>
    );
  };
  //

  goToNews = () => {};
}
//

const styles = StyleSheet.create({
  container: {
    flex: 1
  },
  news_item: {
    flex: 1,
    flexDirection: "row",
    paddingRight: 20,
    paddingLeft: 20,
    paddingTop: 20,
    paddingBottom: 20,
    borderBottomWidth: 1,
    borderBottomColor: "#E4E4E4"
  },
  news_text: {
    flex: 2,
    flexDirection: "row",
    padding: 15
  },
  title: {
    fontSize: 28,
    fontWeight: "bold",
    color: "#000",
    fontFamily: "georgia"
  },
  news_photo: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center"
  },
  photo: {
    width: 120,
    height: 120
  }
});

Running the App

At this point, you should be able to run the app:

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

Try out the app and see if it performs better than React Navigation (if you’ve used it before).

Conclusion and Next Steps

In this tutorial, you learned how to use the React Native Navigation library. Specifically, you learned how to set up React Native Navigation and use the stack and tab navigation. You also learned how to load icons from React Native Vector Icons instead of using image icons.

As a next step, you might want to check out how animations can be customized, how to implement a side menu navigation, or view the examples of different layout types.

Getting Started with GraphQL and React Native

Getting Started with GraphQL and React Native

In this tutorial, you will learn how to implement a simple GraphQL server and query the data from a React Native app.

In 2012, Facebook engineer Nick Schrock started work on a small prototype to facilitate moving away from an old, unsupported partner API that powered the current Facebook News Feed. At the time, this was called “SuperGraph”. Fast forward to today and SuperGraph has helped shape the open-source query language GraphQL, which has been much of the buzzword in recent times.

GraphQL’s adoption is increasing, and for good reason. Many believe it’s the future for API’s, and big companies (GitHub, Coursera, PayPal, Shopify) using it just sparks the developer interest even further.

It’s really an exciting time to learn GraphQL, especially for React Native developers because the apps that we create usually communicate with a server. GraphQL makes it easier for us to get the specific data we want with less code. Gone are the days where we have to hit multiple endpoints just to get the data we want from a REST API.

In this tutorial, you will learn how to implement a simple GraphQL server and query the data from a React Native app.

Prerequisites

Basic knowledge of React Native and Node.js is required to follow this tutorial.

The following package versions are used in this tutorial:

  • Node 11.2.0
  • Yarn 1.13.0
  • React Native CLI 2.0.1
  • React Native 0.59.5

If you encounter any issues getting the app to work, try using the above versions instead.

App overview

We will build a Pokemon viewer app. This will pick a random Pokemon and display it on the screen. When the user taps on it, a new Pokemon will be fetched. It’s really simple but it’s still going to demonstrate how to implement the full GraphQL stack.

You can view the source code of the app on this GitHub repo.

Bootstrapping the app

To ensure compatibility, clone the GitHub repo for this project:

    git clone https://github.com/anchetaWern/RNGraphQL

This contains the package.json file for both the server and the React Native app. The starter branch contains the starting point for this tutorial:

    git checkout starter

Once you’ve switched branches, you can go ahead and install the dependencies and re-create the android and ios folders for the app:

    yarn
    react-native eject

That will install all the GraphQL-related packages that we’re going to need in the app. Later on, you’ll learn what each one does once we proceed to code the client side.

Lastly, we also need to install the server dependencies:

    cd server
    yarn

Creating the GraphQL server

In this section, we will be creating the GraphQL server using Apollo. As you might already know, GraphQL is only a specification, not an implementation. That’s why we need something like Apollo to implement it.

Apollo is a platform which provides us with all the tools needed for implementing a GraphQL server. This includes both the server and the client. The server component is used for defining the schema and resolvers (provides instructions on how to turn a specific GraphQL operation into data). On the other hand, the client component is responsible for providing tools that we can use for querying the server and binding the results to the UI.

Defining the schema

The first step in creating a GraphQL server is for us to define the schema. This is where you strictly define what data your API is managing. In this case, we’re handling basic Pokemon data.

If you’ve seen the demo gif earlier, you know exactly which Pokemon data we’re working with:

  • Name
  • Image
  • Types
  • Description

But aside from that, we also need to define the queries that the server is going to handle. In this case, we’re using the PokéAPI as our direct data source so our queries will be limited by the endpoints they’re exposing. We’re only going to need a few data from these endpoints so it’s fine if we use them directly:

  • /pokemon/{id} - used for getting the Pokemon data.
  • /pokemon-species/{id} - used for getting the description text.

With that in mind, we know that we can only have queries which accept the ID of the Pokemon as its argument.

Note: We’re not really going to cover caching in this tutorial, but it’s important to implement it if you’re going to use an existing REST API as a direct data source. That way, you won’t get throttled from using the API too much. PokéAPI is actually limited to 100 API requests per IP address per minute.

Now we’re ready to define the schema. Create a server/schema.js file and add the following code:

    const { gql } = require('apollo-server');

    const typeDefs = gql`
      type Query {
        pokemon(id: ID!): Pokemon
      }

      type Pokemon {
        id: ID!
        name: String
        desc: String
        pic: String
        types: [PokemonType!]!
      }

      type PokemonType {
        id: Int!
        name: String!
      }
    `;

    module.exports = typeDefs;

Breaking down the above code, we first imported the apollo-server package. This allows us to define the GraphQL schema. The schema includes the shape of the data we expect to return, as well as the shape of the queries.

Let’s first start with the Query type which describes what data we can fetch. In this case, we only want the user to fetch Pokemon data so the query is named pokemon. To specify arguments, you need to put them inside the parentheses right after the name of the query. In this case, we want the users to supply the ID of the Pokemon. An exclamation is added after it to indicate that it is a required argument. After that, we specify the return data after the colon (Pokemon). This is a custom GraphQL object type which we’ll define next:

    type Query {
      pokemon(id: ID!): Pokemon
    }

Next, we need to define the Pokemon object type. This is where we specify all the properties (and their data type) that are available for this particular type. Most of the properties that we need to expose are only scalar types (ID and String):

  • ID is a unique identifier for a specific object of this type. An exclamation is added after it which means it cannot have a value of null.
  • String is just your usual primitive type for storing string values.
  • PokemonType is yet another object type. The types property is used for storing an array of objects so we also have to break down the object to its expected properties:
    type Pokemon {
      id: ID!
      name: String
      desc: String
      pic: String
      types: [PokemonType]
    }

Here’s the definition of the PokemonType:

    type PokemonType {
      id: Int
      name: String
    }

You can find more types on this cheat sheet.

Connect to a data source

Now that we’ve defined our schema, the next step is to connect to a data source. Apollo comes with a data source API, which you could use to easily connect to an existing database or a REST API. As mentioned earlier, we will be using PokéAPI as our data source. This API provides Pokemon data from all of the Pokemon games so it’s perfect for our needs.

Create a server/datasources/poke.js file and add the following:

    const { RESTDataSource } = require('apollo-datasource-rest');

    class PokeAPI extends RESTDataSource {
      constructor() {
        super();
        this.baseURL = 'https://pokeapi.co/api/v2/';
      }

      pokemonReducer(pokemon, pokemonSpecies) {
        return {
          id: pokemon.id || 0,
          name: pokemon.name,
          desc: this.getDescription(pokemonSpecies.flavor_text_entries),
          pic: pokemon.sprites.front_default, // image URL of the front facing Pokemon
          types: this.getTypes(pokemon.types)
        };
      }

      getDescription(entries) {
        return entries.find(item => item.language.name === 'en').flavor_text;
      }

      getTypes(types) {
        return types.map(({ slot, type }) => {
          return {
            "id": slot, // the type's index
            "name": type.name // the type's name (e.g. electric, leaf)
          }
        });
      }

      async getPokemonById({ id }) {
        const pokemonResponse = await this.get(`pokemon/${id}`);
        const pokemonSpeciesResponse = await this.get(`pokemon-species/${id}`);
        return this.pokemonReducer(pokemonResponse, pokemonSpeciesResponse);
      }
    }

    module.exports = PokeAPI;

If you’ve consumed any sort of REST API before (and I assume you have), the code above should easily make sense to you. The apollo-datasource-rest package really makes this simple. This package exposes the RESTDataSource class which allows us to make a request to a REST API:

    const pokemonResponse = await this.get(`pokemon/${id}`); // this.post for POST requests
    const pokemonSpeciesResponse = await this.get(`pokemon-species/${id}`);

From there, all we had to do was to extract the data that we need. The only thing you need to remember is that the data you’re extracting should correspond to the properties that you’ve defined earlier in your schema: id, name, desc, pic, and types:

    pokemonReducer(pokemon, pokemonSpecies) {
      return {
        id: pokemon.id || 0,
        name: pokemon.name,
        desc: this.getDescription(pokemonSpecies.flavor_text_entries),
        pic: pokemon.sprites.front_default, // image URL of the front facing Pokemon
        types: this.getTypes(pokemon.types)
      };
    }

Define the resolvers

The final piece of the puzzle is the resolvers. The resolvers allow us to define the mapping of the queries you’ve defined in your schema to the data source method which returns the data. It follows the format:

    fieldName: (parent, args, context, info) => data;

Here’s what each one does:

  • parent - an object that contains the result returned from the resolver on the parent type. This is always blank (_) because it refers to the root of the graph.
  • args - an object containing the arguments passed to the field. In this case, our query only accepts the id of the Pokemon. We then need to pass the id to the data source method (getPokemonById()) as an object property because that’s how we defined it earlier on the server/datasources/poke.js file.
  • context - this is where we can access our data sources. We can extract the data source from the dataSources property.
  • info - an object which contains information about the execution state of the operation. We don’t really need to use it in this case so we just won’t supply it at all.

To define the resolver, create a server/resolvers.js file and add the following:

    module.exports = {
      Query: {
        pokemon: (_, { id }, { dataSources }) =>
          dataSources.pokeAPI.getPokemonById({ id })
      }
    };

Creating the server

The final step in implementing the GraphQL server is to bring everything together. Create a server/index.js file and add the following:

    const { ApolloServer } = require('apollo-server');
    const typeDefs = require('./schema');
    const resolvers = require('./resolvers');

    const PokeAPI = require('./datasources/poke');

    const server = new ApolloServer({
      typeDefs,
      resolvers,
      dataSources: () => ({
        pokeAPI: new PokeAPI()
      })
    });

    server.listen().then(({ url }) => {
      console.log(`GraphQL Server is running at ${url}`);
    });

In the above code, we import the ApolloServer class from the apollo-server package. This allows us to fire up an Apollo server which accepts an object containing the schema, resolvers, and data sources we’ve defined earlier.

At this point, you can now run the server:

    cd server
    yarn start

You can play around with it by accessing http://localhost:4000/ on your browser.

If you get a blank screen, delete the node_modules folder and yarn.lock file. After that, remove the dependencies property in the package.json file and re-install the dependencies with the following command:

    yarn add [email protected] [email protected] [email protected]

From there, you can view the schema that we’ve defined earlier by clicking on the SCHEMA tab located on the right part of the screen:

But this interface is mostly used for testing out your queries. In this case, we want to fetch the Pokemon with the ID of 25:

    query GetPokemonByName {
      pokemon(id: 25) {
        id,
        name,
        desc,
        pic
      }
    }

That will return the following result:

    {
      "data": {
        "pokemon": {
          "id": "25",
          "name": "pikachu",
          "desc": "Its nature is to store up electricity. Forests\nwhere nests of Pikachu live are dangerous,\nsince the trees are so often struck by lightning.",
          "pic": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/25.png"
        }
      }
    }

What if we also want to get the types of the Pokemon? Intuitively, we would just add types to the properties we’ve specified:

    query GetPokemonByName {
      pokemon(id: 25) {
        id,
        name,
        desc,
        pic,
        types
      }
    }

But that’s going to return an error:

The error says:

The field types of type [PokemonType] must have a selection of subfields.

This means that you also need to specify the subfields that you want to fetch like so:

    query GetPokemonByName {
      pokemon(id: 25) {
        id,
        name,
        desc,
        pic,
        types {
          id,
          name
        }
      }
    }

That will return the following:

    {
      "data": {
        "pokemon": {
          "id": "25",
          "name": "pikachu",
          "desc": "Its nature is to store up electricity. Forests\nwhere nests of Pikachu live are dangerous,\nsince the trees are so often struck by lightning.",
          "pic": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/25.png",
          "types": [
            {
              "id": 1,
              "name": "electric"
            }
          ]
        }
      }
    }
Building the app

Now that we’re done implementing the server, it’s time for us to add the code for the React Native app. Open the App.js file and add the following:

    import React, { Component } from "react";
    import { View, Text, ActivityIndicator } from "react-native";

    import { ApolloProvider, Query } from "react-apollo";
    import ApolloClient from "apollo-boost";
    import gql from "graphql-tag";

Here’s what each package does:

  • apollo-boost - used for connecting to an Apollo server.
  • react-apollo - provides React components that allows us to fetch data from the Apollo server.
  • graphql-tag - used for parsing GraphQL queries into a format understood by the Apollo client.

Next, connect to the server that we created earlier. Replace the placeholder with your machine’s internal IP address. Be sure that your machine and your device are connected to the same network when you do so. You can also use ngrok if you want:

    const client = new ApolloClient({ uri: 'http://YOUR_INTERNAL_IP_ADDRESS:4000/graphql' })

Next, import the component for rendering the Pokemon data as well as the helper function for generating random integers:

    import Pokemon from "./src/components/Pokemon";
    import getRandomInt from "./src/helpers/getRandomInt";

Next, we’re going to use the Context API so we can pass the Pokemon data through the component tree without having to pass props needed by the Pokemon component down manually at every level:

    export const AppContext = React.createContext({ data: { pokemon: null } });

Next, create the component and declare its default state. The query contains the same query that we used earlier. We’re putting it in the state so the component will re-render every time we update it:

    export default class App extends Component {

      state = {
        query: null
      }

      // next: add componentDidMount
    }

Once the component is mounted, we generate the query and update the state:

    componentDidMount() {
      const query = this.getQuery();
      this.setState({
        query
      });
    }

Here’s the getQuery() function. This generates a random ID and uses it for the query:

    getQuery = () => {
      const randomID = getRandomInt(1, 807);
      return `
        query GetPokemonById {
          pokemon(id: ${randomID}) {
            id,
            name,
            desc,
            pic,
            types {
              id,
              name
            }
          }
        }
      `
    }

In the render() method, the <ApolloProvider> component is where we pass the client we created with the ApolloClient earlier. Then we add the <Query> component as its child, this is where you pass the query. Don’t forget to parse the query with the gql module. By default, loading will have a value of true. In that case, we show a loading animation. Once the server responds, it can either be an error or data. The data contains the same data you saw earlier when we tried running some queries. From there, we just pass the Pokemon data and the function for fetching a new one to the app’s context:

    render() {
      const { query } = this.state;
      if (!query) return null;

      return (
        <ApolloProvider client={client}>
          <Query query={gql`${query}`} >
            {({ loading, error, data }) => {
              if (loading || error) return <ActivityIndicator size="large" color="#0000ff" />
              return (
                <AppContext.Provider value={{...data.pokemon, onPress: this.onGetNewPokemon}} style={styles.container}>
                  <Pokemon />
                </AppContext.Provider>
              )
            }}
          </Query>
        </ApolloProvider>
      );
    }

Here’s the onGetNewPokemon() function:

    onGetNewPokemon = () => {
      const query = this.getQuery();
      this.setState({
        query
      });
    }

getRandomInt helper

Here’s the helper for generating random integers. Create the src/helpers folder to house it:

    // src/helpers/getRandomInt.js
    const getRandomInt = (min, max) => {
      min = Math.ceil(min);
      max = Math.floor(max);
      return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    export default getRandomInt;

Pokemon component

The Pokemon component is used for displaying the Pokemon data. Create a src/components folder to house it.

Start by importing the packages we need:

    // src/components/Pokemon.js
    import React from 'react';
    import { View, Text, Image, FlatList, TouchableOpacity } from 'react-native';
    import { AppContext } from '../../App'; // import the context we exported earlier on the App.js file

Next, render the component. Wrap it in <AppContext.Consumer> so you get access to the data and the onPress function that we passed to the context earlier. From there, it’s just a matter of displaying the data using the right components:

    const Pokemon = () => {
      return (
        <AppContext.Consumer>
          {
            ({ name, pic, types, desc, onPress }) =>
            <TouchableOpacity onPress={onPress}>
              <View style={styles.mainDetails}>
                <Image
                  source={{uri: pic}}
                  style={styles.image} resizeMode={"contain"} />
                  <Text style={styles.mainText}>{name}</Text>

                  <FlatList
                    columnWrapperStyle={styles.types}
                    data={types}
                    numColumns={2}
                    keyExtractor={(item) => item.id.toString()}
                    renderItem={({item}) => {
                      return (
                        <View style={[styles[item.name], styles.type]}>
                          <Text style={styles.typeText}>{item.name}</Text>
                        </View>
                      )
                    }}
                  />

                  <View style={styles.description}>
                    <Text>{desc}</Text>
                  </View>
              </View>
            </TouchableOpacity>
          }
        </AppContext.Consumer>
      );
    }

Lastly, add the styles and export the component. Most of these are just used to change the background color of the types container based on the Pokemon’s type:

    const styles = {
      mainDetails: {
        padding: 30,
        alignItems: 'center'
      },
      image: {
        width: 100,
        height: 100
      },
      mainText: {
        fontSize: 25,
        fontWeight: 'bold',
        textAlign: 'center'
      },
      description: {
        marginTop: 20
      },
      types: {
        flexDirection: 'row',
        marginTop: 20
      },
      type: {
        padding: 5,
        width: 100,
        alignItems: 'center'
      },
      typeText: {
        color: '#fff',
      },
      normal: {
        backgroundColor: '#8a8a59'
      },
      fire: {
        backgroundColor: '#f08030'
      },
      water: {
        backgroundColor: '#6890f0'
      },
      electric: {
        backgroundColor: '#f8d030'
      },
      grass: {
        backgroundColor: '#78c850'
      },
      ice: {
        backgroundColor: '#98d8d8'
      },
      fighting: {
        backgroundColor: '#c03028'
      },
      poison: {
        backgroundColor: '#a040a0'
      },
      ground: {
        backgroundColor: '#e0c068'
      },
      flying: {
        backgroundColor: '#a890f0'
      },
      psychic: {
        backgroundColor: '#f85888'
      },
      bug: {
        backgroundColor: '#a8b820'
      },
      rock: {
        backgroundColor: '#b8a038'
      },
      ghost: {
        backgroundColor: '#705898'
      },
      dragon: {
        backgroundColor: '#7038f8'
      },
      dark: {
        backgroundColor: '#705848'
      },
      steel: {
        backgroundColor: '#b8b8d0'
      },
      fairy: {
        backgroundColor: '#e898e8'
      }
    }

    export default Pokemon;
Running the app

At this point, you can now run the app:

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

Conclusion

That’s it! In this tutorial, you learned the basics of using GraphQL in a React Native app. Specifically, you learned how to set up your own GraphQL server using Apollo, use an existing REST API as its data source, consume the data from a React Native app, and display it to the user.

Even though we’ve implemented the full stack on this tutorial, there’s still a lot more to learn. Be sure to check out the GraphQL and Apollo docs to learn more.

You can view the source code of the app on this GitHub repo.

How to build a news app with JavaScript and React Native

How to build a news app with JavaScript and React Native

How to build a news app with JavaScript and React Native

Requirements for building the app:

  • A basic understanding of the JavaScript language.
  • Node.js, and react native.
  • Libraries used: moment, react-native, react-native-elements.

If you’re not familiar with these resources, don’t worry — they are quite easy to use.

The topics we will cover in the post are:

  • A basic understanding of the JavaScript language.
  • Node.js, and react native.
  • Libraries used: moment, react-native, react-native-elements.

And more…so let’s get started!

You can find the full project repo HERE.

News API

A simple and easy-to-use API that returns JSON metadata for headlines and articles live all over the web right now. — NewsAPI.org
First, you should go ahead and sign up for News Api to get your free apiKey (your authentication key).

Create a new React Native project, and call it news_app (or whatever you want). In the project directory, make a new folder and call it src . In srccreate a folder an name it components . So your project directory should look something like this:

In the src folder, create a new file called news.js . In this file we are going to fetch the JSON that contains the headlines from the News API.

news.js
const url =
  "https://newsapi.org/v2/top-headlines?country=us&apiKey=YOUR_API_KEY_HERE";

export async function getNews() {
  let result = await fetch(url).then(response => response.json());
  return result.articles;
}

Make sure you replace YOUR_API_KEY_HERE with your own API key. For more information about the News API, go to newsapi docs.

Now we declare the getNews function, which is going to fetch the articles for us. Export the function so we can use it in our App.js file.

App.js
import React from 'react';
import { FlatList } from 'react-native';

// Import getNews function from news.js
import { getNews } from './src/news';
// We'll get to this one later
import Article from './src/components/Article';

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { articles: [], refreshing: true };
    this.fetchNews = this.fetchNews.bind(this);
  }
  // Called after a component is mounted
  componentDidMount() {
    this.fetchNews();
   }

  fetchNews() {
    getNews()
      .then(articles => this.setState({ articles, refreshing: false }))
      .catch(() => this.setState({ refreshing: false }));
  }

  handleRefresh() {
    this.setState(
      {
        refreshing: true
    },
      () => this.fetchNews()
    );
  }

  render() {
    return (
      <FlatList
        data={this.state.articles}
        renderItem={({ item }) => <Article article={item} />}
        keyExtractor={item => item.url}
        refreshing={this.state.refreshing}
        onRefresh={this.handleRefresh.bind(this)}
      />
  );
  }
}

In the constructor, we define the initial state. articles will store our articles after we fetch them, and refreshing will help us in refresh animation. Notice that I setrefreshing to true, because when we start the app, we want the animation to start while we load the articles.

componentDidMount is invoked immediately after a component is mounted. Inside it we call the fetchNews method.

componentDidMount() {
  this.fetchNews();
}

In fetchNews we call getNews() which returns a promise. So we use the .then() method which takes a callback function, and the callback function takes an argument (the articles).

Now assign the articles in the state to the articles argument. I only typed articles because it’s a new ES6 syntax that means { articles: articles } , and we set refreshing to false to stop the spinner animation.

fetchNews() {
  getNews().then(
      articles => this.setState({ articles, refreshing: false })
  ).catch(() => this.setState({ refreshing: false }));
}

.catch() is called in rejected cases.

handleRefresh starts the spinner animation and call fetchNews(). We pass () => this.fetchNews() , so it’s called immediately after we assign the state.

handleRefresh() {
  this.setState({ refreshing: true },() => this.fetchNews());
}

In the render method, we return a FlatList element. Then we pass some props. data is the array of articles from this.state. The renderItem takes a function to render each item in the array, but in our case it just returns theArticle component we imported earlier (we’ll get there). And we pass the article item as a prop to use later in that component.

Article.js

In src/components create a new JavaScript file and call it Article.js.

Let’s start by installing two simple libraries using npm: react-native-elements, which gives us some premade components we could use, and moment that will handle our time.

run using terminal/cmd:

npm install --save react-native-elements moment

In Article.js:

import React from 'react';
import { View, Linking, TouchableNativeFeedback } from 'react-native';
import { Text, Button, Card, Divider } from 'react-native-elements';
import moment from 'moment';

export default class Article extends React.Component {
  render() {
    const {
      title,
      description,
      publishedAt,
      source,
      urlToImage,
      url
    } = this.props.article;
    const { noteStyle, featuredTitleStyle } = styles;
    const time = moment(publishedAt || moment.now()).fromNow();
    const defaultImg =
      'https://wallpaper.wiki/wp-content/uploads/2017/04/wallpaper.wiki-Images-HD-Diamond-Pattern-PIC-WPB009691.jpg';

    return (
      <TouchableNativeFeedback
        useForeground
        onPress={() => Linking.openURL(url)}
      >
        <Card
          featuredTitle={title}
          featuredTitleStyle={featuredTitleStyle}
          image={{
            uri: urlToImage || defaultImg
          }}
        >
          <Text style={{ marginBottom: 10 }}>
            {description || 'Read More..'}
          </Text>
          <Divider style={{ backgroundColor: '#dfe6e9' }} />
          <View
            style={{ flexDirection: 'row', justifyContent: 'space-between' }}
          >
            <Text style={noteStyle}>{source.name.toUpperCase()}</Text>
            <Text style={noteStyle}>{time}</Text>
          </View>
        </Card>
      </TouchableNativeFeedback>
    );
  }
}

const styles = {
  noteStyle: {
    margin: 5,
    fontStyle: 'italic',
    color: '#b2bec3',
    fontSize: 10
  },
  featuredTitleStyle: {
    marginHorizontal: 5,
    textShadowColor: '#00000f',
    textShadowOffset: { width: 3, height: 3 },
    textShadowRadius: 3
  }
};

There is a lot going on here. First, we start by destructuring the articleprop and the styles object defined below the class.

In render we define time to store the time for when the article was published. We use the moment library to convert the date to the time passed since then, and we pass publishedAt or time from now if publishedAt is null.

defaultImg is assigned an image URL in case the URL of the article image is null.

The render method returns TouchableNativeFeedback (use TouchableOpacityinstead if it does not work on your platform) to handle when the user presses the card. We pass it some props: useForground which tells the element to use the foreground when displaying the ripple effect on the card, and onPress , which takes a function and executes it when the user presses the card. We passed () => Linking.openUrl(url) which simply opens the URL to the full article when we press the card.

The card takes three props: featuredTitle which is just a fancy title placed over the image you could use title instead if you want, featuredTitleStyle to style it, and image which is the article image from the article prop. Otherwise, if its null , it’s going to be the defaultImg.

..
  featuredTitle={title}
  featuredTitleStyle={featuredTitleStyle}
  image={{ uri: urlToImage || defaultImg }}
..

As for the text element, it will hold the description for the article.

<Text style={{ marginBottom: 10 }}>{description}

We added a divider to separate the description from time and source name.

<Divider style={{ backgroundColor: '#dfe6e9' }} />

Below the Divider , we have a View that contains the source name and the time the article was published.

..
<View 
  style={{ flexDirection: ‘row’, justifyContent: ‘space-between’ }} > 
  <Text style={noteStyle}>{source.name.toUpperCase()}</Text>
  <Text style={noteStyle}>{time}</Text>
</View>
..

After the class, we defined the styles for these components.

Now if we run the app:

There you go! The source code for the app is available on GitHub HERE you can improve upon it and make a pull request😄.