Advertisement
  1. Code
  2. React Native
Code

Code an App With GraphQL, React Native and AWS AppSync: The App

by
Difficulty:IntermediateLength:LongLanguages:
Final product image
What You'll Be Creating

In these tutorials, I'm showing you how to create and interact with a GraphQL database using AWS AppSync and React Native. This app will have real-time and offline functionality, something we get out of the box with AppSync. 

In the previous post, we set up our GraphQL back-end with the Amazon AppSync service. Check it out if you haven't already. Or, if you want an introduction to GraphQL, take a look at some of our other posts.

In this post, we'll wrap it all up by walking through the build of the React Native client. The project is a bit too complicated to walk you through step by step, but I'll explain the project architecture and show you the key parts of the source code.

Overview of the App Architecture and Folder Structure

Our application will have a main entry point that will consist of two tabbed views. One tab will list the cities from our GraphQL database, and the other will be the input form to add a new city. The Cities tab will be a navigator that will allow the user to navigate to the individual cities.

We will store the main components in the source folder, and will have other folders in the src directory to hold our GraphQL mutations, queries, and subscriptions.

We will also have an assets folder to hold our images.

folder structure

Creating and Configuring the React Native Client

For reference, take a look at the final code for this app in the tutorial GitHub repo, but I'll outline some of the steps I took to create the app from scratch.

First, we created a new React Native application using Expo

Once in the newly created project, we installed our dependencies. For the GraphQL and AppSync functionality, we used the following dependencies:

We also used the following dependencies for the UI design:

Also, once the Vector Icons library was installed, we linked it:

After installing our dependencies, we downloaded the AppSync.js file from our AppSync console. In our AppSync project console, we chose React Native at the bottom, and clicked on the orange Download button to download this config file.

downloading the AppSyncjs file from our AppSync console

This config file holds the AppSync client information we needed to create a new client. 

Configuring the Provider and Store

The top level of the app is where we will do our configuration to wire up the AppSync API with the React Native client. If you have used Redux or React Apollo before, this will all be familiar. If you have not, just remember that any child of a Provider, in our case the ApolloProvider, will have access to its given functionality. 

The following code is our new App.js file, which is the main component imported from our index.js entrypoint.

In this file, we are setting up a new AppSync client using a combination of the AWSAppSyncClient constructor from aws-appsync as well as the configuration in our aws-exports.js file, which provides the GraphQL API URL, region, authentication type, and authentication API key.

We then wrap our main entrypoint, the Tabs.js file which will hold our tab navigation, in an ApolloProvider and pass in the AppSync client as the client prop. We also wrap the Tabs component in a Rehydrated component that we import from aws-appsync-react. This will make sure that we have read from async storage and have rehydrated our cache before rendering the UI.

Now our app will be able to query data from our AppSync endpoint, and also to perform mutations and subscriptions!

Navigation

The main entry point of the app is a tabbed navigation, implemented in the Tabs.js file with React Navigation.

What we've done here is create and export a TabNavigator with two tabs. These are:

  1. Cities: This component lists our cities, and it is a navigator component in and of itself. This component is a navigator because we want to be able to navigate to each individual city and view the locations within the city.
  2. AddCity: This component is a form for us to be able to add new cities.
The Cities screen in the app

Reusable Components

This app has only one reusable component, a customized TextInput. Since we will be duplicating this style and functionality over and over, we decided to make it its own component. The input component is implemented in Input.js.

Cities List and City Navigation

The main view of the app is a list of cities that we will be retrieving from GraphQL. We want to be able to navigate from each listed city to a detail view of that city where we can add locations.

To do this, we make Cities.js its own StackNavigator, and City.js the component we navigate to when choosing a city. When clicking on a city in Cities, we pass its name and id as props to City.

Cities.js

In this component, we are fetching using the listCities query, and we are also subscribing to the NewCitySubscription, so that when a new city is added, even from another client, we'll handle that subscription and update our array of cities. The listCities query makes an array of cities available in our component as this.props.cities.

City.js

In this component, we are passed a city as props from navigation (available as props.navigation.state.params.city). We use the city id value to fetch the list of locations for the chosen city using the listLocations query. We subscribe to new locations in a similar way to how we subscribed to new cities in Cities.js, using the NewLocationSubscription subscription. We also provide optimisticResponse and update functions for when a new city is added. 

Adding Cities

Finally, we need to implement the functionality for adding new cities to our GraphQL API in the AddCity.js file. To do this, we have wired up a mutation along with a form that will call createCity, passing the value of the form input.

AddCity has an onAdd function that we define in our GraphQL composition, which not only writes a new city to our GraphQL database, but also implements an optimistic UI using a combination of optimisticResponse and update.

Mutations, Queries, and Subscriptions

Mutations, queries, and subscriptions are the core functionality for integrating with our GraphQL API. In our app, this functionality is implemented in the Cities.js, City.js, and AddCity.js files using the AppSync client.

Let's take a closer look at how mutations, queries, and subscriptions are implemented in our code.

Queries

First, let's look at how to create and export a GraphQL query that could interact with the listCities query in our AppSync Schema. This code is contained in the src/queries/ListCities.js file.

Next, we import this query in the Cities.js file, along with some helpers from react-apollo, and wire up the component that we would like to have access to this data using compose and graphql from react-apollo.

Now we have access to the cities array from our GraphQL server as a prop. We can use this.props.cities to map over the cities array coming in from GraphQL.

Mutations

To create a mutation, first we need to create a basic GraphQL mutation and export it. We do this in the src/mutations/CreateCity.js file.

Now we can import this mutation (along with the Apollo helpers) in the AddCity.js file and use it in a component: 

Now, we have access to a prop called onAdd, which we pass an object we would like to send to the mutation!

Subscriptions

Subscriptions allow us to subscribe to data changes and have them update in our application in real time. If we were to change our database by adding or removing a city, we would like our app to update in real time.

First, we need to create the mutation and export it so we can have access to it within the client. We save this in the src/subscriptionsNewCitySubscriptions.js file.

Now we can import and attach the subscription in Cities.js. We already looked at how to get the cities from our API. Let's now update this functionality to subscribe to new changes and update the cities array when a new city is added.

We add a new prop called subscribeToNewCities, which we call in componentDidMount. In the subscription, we pass in a document (the subscription definition) and updateQuery to describe what we want to happen when this updates.

We destructure createCity (containing the mutation) from the props that are passed into the updateQuery function, and return all existing values along with an updated listCities  array containing the previous cities along with the new city data that we get from createCity.

Optimistic UI

What if we don't want to wait for the subscription to return the most up-to-date data from our API in order to update our UI?

If a user creates a new city, we want to automatically add it the cities array and have it render in our app before receiving confirmation from the back-end service.

We can do that easily using a few techniques and functions.

Let's update our AddCityMutation to the following (you can view this code in the AddCity.js source file):

Here, we've added two new properties to the mutate function argument object:

  1. optimisticResponse defines the new response you would like to have available in the update function.
  2. update takes two arguments, the proxy (which allows you to read from the cache) and the data you would like to use to make the update. We read the current cache (proxy.readQuery), add it our new item to the array of items, and then write back to the cache, which updated our UI.

Conclusion

GraphQL is becoming more and more mainstream. Much of the complexity surrounding GraphQL has to do with managing the back end and the API layer. However, tools like AppSync abstract away this complexity, freeing developers from spending most of their time configuring and working on the server.

I look forward to much more innovation in this space, and can't wait to see what else we will see in 2018!

If you're interested in using AppSync along with the Serverless framework, check out this great introduction to using the two of them together.

If you would like to learn more about AWS AppSync, I would suggest taking a look at the AppSync homepage and the documentation for building a GraphQL client.

If you want to contribute to this project, you can connect to our GitHub repo. If you have any ideas, feel free to send us a PR, or use this app as a starter for your next React Native GraphQL project!

And in the meantime, check out some of our other React Native tutorials here on Envato Tuts+!

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.