A tutorial to build a React Native to-do app with Apollo’s new Query and Mutation components
Overview
In this tutorial, we will be building a React Native to-do app that helps us add tasks, view them, mark/unmark them as complete and delete them.

To build the above app, we will be using:
- React Native
- Apollo Client
- GraphQL backend using The Hasura platform
- React Native Auth Boilerplate for ready-made authentication
Note: We will be using the new Query and Mutation components that Apollo introduced in their 2.1.3 release of react-apollo.
Setting up the backend
We need a GraphQL backend along with a database and authentication. Therefore, we will use the Hasura platform which has all three. To get a base Hasura project,
- Install Hasura CLI
- Clone the base Hasura project :
$ hasura quickstart base todo-app-backend
- Activate your backend using a
git push
:
$ cd todo-app-backend
Creating a table
For our to-do app, we will need a table with the following fields.
todos
+-----------+------------------------------+
| column | type |
+-----------+------------------------------+
| id | serial NOT NULL primary key |
| task | text NOT NULL |
| completed | boolean NOT NULL |
| user_id | integer NOT NULL |
+-----------+------------------------------+
Here is the significance of the columns:
- id: This is a unique integer that will identify each task. It is also the primary key of the table.
- task: This is the to-do task.
- completed: This is a boolean flag that marks the task as completed and pending.
- user_id: This is the user_id associated with the user that enters the task.
Lets create the above table in our backend:
- Open the UI console by running the following command from the
todo-app-backend
directory:
$ hasura api-console
- Go to the
Data
section on top and click on “Create Table” and add the aforementioned column names and types.

- The GraphQL backend is ready once you have created the table. You can try out the queries and mutations in the
API Explorer
button.
Table Permissions
By default, every table created on the Hasura platform only has admin permissions set on it. This means that only admin users are allowed to fetch and modify data from tables by default.
Every user created using the Hasura paltform’s authentication APIs is given a user
role by default. Since we are going to be using the Hasura platform to add authentication to our react-native app, we need to add permissions to the todos
table. The permissions should allow users to fetch, add, update and delete their own todos. Fortunately, this also can be easily done on the API Console
.
Go to the Data
section in the API console and select the todos
table on the left panel. You can modify the table permissions in the Permissions
tab.
Click on insert
and add the permissions as shown below

The above permission means that for every row inserted into this table, the user_id
should be the same as the id
of the Hasura user who is making the insert request.
Similarly, set permissions for select, update and delete



Note: The columns selected for select
permissions are the columns whose value a user should be allowed to fetch from the table. We allow select on all columns. Similarly, the selected columns for the update
permission are the columns whose data can be modified once they have been inserted into the table. In this case, we only allow update on completed
and task
.
Our modelling for the todo app is now complete. Next, we need to figure out authentication for our app.
Authentication
A robust to-do app needs some kind of a login screen. Since auth
is not the primary focus of this tutorial, we will be using the React Native Auth Boilerplate that has authentication already implemented along with boilerplate code for a basic React Native app.
Clone the boilerplate to get started. Also, rename your project and cd into it:$ cp react-native-auth-boilerplate/vanilla ./todo-app -r
$ cd todo-app
$ git clone https://github.com/hasura/react-native-auth-boilerplate
Install node_modules
related to the the boilerplate:
$ npm install
Also, enter your clustername in theHasura.js
file inside the todo-app
directory so that authentication is handled by the Hasura platform APIs. (Run $ hasura cluster status
from the todo-app-backend
directory to find your cluster name)//replace "clustername45" with your cluster name
const clusterName = "clustername45";
Configuring Apollo Client
Let us install the dependencies related to Apollo client. Run the following command from the todo-app
directory.
$ npm install apollo-boost react-apollo graphql-tag graphql --save
Next, create an instance of Apollo client in the App. src/AppScreen.js
is the entry component, so it is the right place to instantiate the client. We also need to authenticate our requests using the session token. The React Native Auth Boilerplate stores the session token to the AsyncStorage
of the mobile device with a key @<clusterName>:myapp
. To instantiate a client and add the session information in the request, make the src/Appscreen.js
look like this:
Next, we have to connect the Apollo client with our app. To do that, we need to wrap our root component inside ApolloProvider
. Your src/AppScreen.js
should finally look like:
Writing GraphQL queries and mutations
Lets make a new file called queries.js
in the src
directory to store all the GraphQL queries and mutations that we need for the app. We will declare the queries as gql
strings. gql
lets you write your queries with ES2015 template literals and compile them into an AST with the gql
tag.
Our queries.js
will look like:
Creating our first Query component
Apollo Client recently released the new Query and Mutation components that work somewhat like renderProps
. The flow goes like:
import {Query} from 'react-apollo';
- Pass the GraphQL query string as prop to the
Query
component.
<Query query={gql`GRAPHQL_QUERY`}>
- Wrap your custom component inside the
Query
component.
<Query query={gql`GRAPHQL_QUERY`}>
MyComp
in the above component received the state and response of the GraphQL query.
We will write our TodoListComponent
similary. Create a file called TodoListComponent.js
in the src
directory. Write a TodoListComponent
using the Query component, similar to what is shown above. It will look something like:
The above component simply fetches all the todos
and renders them in a flatlist.
Writing our first Mutation component
Mutation components work just like the Query components. In case of mutations, we also need to update the UI after the mutation succeeds.
Create a file called AddButton.js
and add the following content to it:
Similarly create aDeleteButton.js
too.
Finally, we need an update mutation to mark the tasks as completed and incomplete. We will simply make clickable text and render it in the Flatlist.
Create a file called TodoTextItem.js
Wrapping it up
Now, we need to render the TodoTextItem
and DeleteButton
components with every to-do task in the Flatlist. Go back to TodoListComponent.js
and add TodoTextItem
and DeleteButton
in the Flatlist. The file will finally look like this:
Finally lets put all of these together in an index component called TodoApp.js.
TodoApp
will have the AddButton
that we created, a textbox and a logout button. On logout, we need to reset the Apollo store using resetStore
because the queries are cached in the store.
The TodoApp component looks like:
Running the app
- For android:
$ react-native run-android
- For iOS:
$ react-native run-ios
Please comment if you have any questions. You can find the complete code for the app we created, in this github repository.