Building Chatty — Part 3: GraphQL Queries with React Apollo

A WhatsApp clone with React Native and Apollo

Simon Tucker
React Native Training
15 min readApr 9, 2017

--

This is the third blog in a multipart series where we will be building Chatty, a WhatsApp clone, using React Native and Apollo. You can view the code for this part of the series here.

Here’s what we will accomplish in this tutorial:

  1. Create the basic layout for our React Native application
  2. Build GraphQL Queries using react-apollo

First we’re going to need a few packages:

  • lodash is a top notch utility library for dealing with data in JS
  • moment is the goto package for dealing with Dates in JS
  • graphql-tag lets us parse GraphQL Queries from strings
  • prop-types is a runtime type checker for React props and similar objects
  • randomcolor will let us generate random colors
  • react-navigation is a collaboration between people from Facebook, Exponent and the React community to create the best navigation solution for the React ecosystem

Creating the Layout

I’m a visual guy, so I like to first establish the general look and feel of the app before adding data.

Using react-navigation, we can design routing for our application based on Screens. A Screen is essentially a full screen or collection of sub-screens within our application. It’s easiest to understand with a basic example.

Let’s create a new file client/src/navigation.js where we will declare the navigation for our application:

Step 3.1: Create AppWithNavigationState

Changed client/package.json

Added client/src/navigation.js

This setup will create a StackNavigator named AppNavigator that will hold all our Screens. A StackNavigator stacks Screens on top of each other like pancakes when we navigate to them.

Within AppNavigator, we can add different Screens and other Navigators that can be pushed onto the stack.

MainScreenNavigator is a TabNavigator, which means it organizes Screens in tabs. The Screens within MainScreenNavigator are just placeholders which display the title of the Screen for now. MainScreenNavigator will be our default view, so we've added it as the first Screen in AppNavigator.

We also have created a basic reducer for our navigator (navigatorReducer) to track navigation actions in Redux. We use connect from react-redux to connect our AppNavigator to Redux.

We can update app.js to use our new Redux connected AppWithNavigationState component and combine navigationReducer with our apollo reducer:

Step 3.2: Connect Navitgation to App

Changed client/src/app.js

Refresh the app to see some simple tabs:

On the Chats tab, we want to show a list of the user’s groups. We’ll create a Groups screen component in a new file client/src/screens/groups.screen.js:

Step 3.3: Create Groups Screen

Added client/src/screens/groups.screen.js

And insert Groups into our AppNavigator:

Step 3.3: Create Groups Screen

Changed client/src/navigation.js

When the user presses one of the rows in our FlatList, we want to push a new Screen with the message thread for the selected group. For this Screen, we’ll create a new Messages component which will hold a list of Message components:

Step 3.4: Create Messages Screen

Added client/src/screens/messages.screen.js

We’ll also write the code for the individual Message components that populate the FlatList in Messages:

Step 3.5: Create Message Component

Added client/src/components/message.component.js

We add Messages to AppNavigator so it will stack on top of our Main screen when we navigate to it:

Step 3.6: Add Messages to Navigation

Changed client/src/navigation.js

Finally, modify Groups to handle pressing a Group. We can use props.navigation.navigate, which is passed to our Groups component via React Navigation, to push the Messages Screen:

Step 3.6: Add Messages to Navigation

Changed client/src/screens/groups.screen.js

Our app should now have simple layouts and routing for showing groups and pressing into a group to show that group’s message thread:

sweeeeeet

GraphQL Queries with React-Apollo

Time to connect our data!

On our server, we created a user query which will give our client access to plenty of data for a given User. Let’s use this query in our Groupscomponent to get the user’s list of groups. It’s good form to keep queries separate of components because queries can often be reused by multiple components. We will create a new folder client/src/graphql to house all our queries, and create user.query.js inside this folder:

Step 3.7: Create USER_QUERY

Added client/src/graphql/user.query.js

This query should look just like something we would insert into GraphQL Playground. We just use graphql-tag to parse the query so that our client will make the proper GraphQL request to the server.

Inside groups.screen.js, we will import USER_QUERY and connect it to the Groups component via react-apollo. react-apollo exposes a graphql module which requires a query, and can be passed an Object with optional configuration parameters as its second argument. Using this second argument, we can declare variables that will be passed to the query:

When we apply userQuery to the Groups component, Groups’ props will now also contain a data property with a loading parameter and the name of our Query (user):

When the Query is loading, props.data.loading will be true and props.data.user will be undefined. When data is returned, props.data.loading will be false and props.data.user will be populated. There is also a neat trick we can do using the propsparameter of options we pass to graphql:

By using the props parameter in the graphql options, we can shape how we want the data to look on our component’s props. Here, we eliminate the data piece from Groups.props and directly place loading and user onto Groups.props.

Finally, we’ll modify our Groups component to render a loading screen while we are loading, and a list of Groups once we receive the data:

Step 3.8: Apply USER_QUERY to Groups

Changed client/src/screens/groups.screen.js

By passing in {id: 1} for our variables, we are pretending to be logged in as the User with id = 1. In Part 7 of these tutorials, we will add authentication to our application so we don’t have to fake it anymore.

With our server running, if we refresh the application, we should see the groups displayed for User id = 1:

A Few Different Ways to Connect GraphQL and React

react-apollo actually gives us multiple ways to connect data from a GraphQL Query to a React component.

  1. The most straightforward way is to use the graphql module from react-apollo:

2. withApollo gives direct access to your ApolloClient instance as a prop to your wrapped component. If you’re trying to do something fancy with custom logic like a one-off query, this module let’s you take charge of how your component gets its data:

3. My personal favorite method is the react-apollo compose module, which makes it easy to elegantly attach multiple queries, mutations, subscriptions, and your Redux store to the component in a single assignment:

Getting Messages

I think this might be a good moment to reflect on the coolness of GraphQL.

In the olden days, to get data for the Screen for our Messages, we might start by consuming a REST API that gets Messages. But later down the line, we might also need to show details about the Group. In order to accomplish this, we would either have to make calls to different endpoints for Group details and Messages associated with the Group, or stuff the Messages into our Group endpoint. Womp.

With GraphQL, we can run a single call for exactly what we need in whatever shape we want. We can think about getting data starting with a node and going down the graph. In this case, we can query for a Group, and within that Group, request the associated Messages in the amount we want, and modify that amount when we need.

This time, let’s try using compose. Our process will be similar to the one we used before:

  1. Create a GraphQL Query for getting the Group
  2. Add configuration params for our Query (like a variable to identify which Group we need)
  3. Use the react-apollo graphql module to wrap the Messages component, passing in the Query and configuration params. We’ll also use compose just to get a feel for it. Let’s start by creating our query in client/src/graphql/group.query.js:

Step 3.9: Create GROUP_QUERY

Added client/src/graphql/group.query.js

So this Query is pretty cool. Given a groupId, we can get whatever features of the Group we need including the Messages. For now, we are asking for all the Messages in this Group. That’s a good starting point, but later we’ll modify this query to return a limited number of Messages at a time, and append more Messages as the user scrolls.

Finally, let’s attach our GROUP_QUERY to the Messages component:

Step 3.10: Apply GROUP_QUERY to Messages

Changed client/src/screens/messages.screen.js

If we fire up the app, we should see our messages:

starting to look like the real thing….

Looking good!

That’s it for Part 3. In the next part of this series, we will add GraphQL Mutations to our server and client so our users can send messages.

As always, please share your thoughts, questions, struggles, and breakthroughs below!

You can view the code for this tutorial here

Continue to Building Chatty — Part 4 (GraphQL Mutations & Optimistic UI)

--

--