Run mutation, update cache

Firstly, let us define the mutation that we looked at in the previous section. Import gql from graphql-tag and define the following mutation in src/screens/components/Todo/Textbox.js.

githubTextbox.js
+ import gql from 'graphql-tag';
+const INSERT_TODO = gql`
+ mutation ($text: String!, $isPublic: Boolean){
+ insert_todos (
+ objects: [{
+ title: $text,
+ is_public: $isPublic
+ }]
+ ){
+ returning {
+ id
+ title
+ is_completed
+ created_at
+ is_public
+ user {
+ name
+ }
+ }
+ }
+ }
`;

Now let's do the integration part. Now add the following code below the other imports:

+ import { useMutation } from "@apollo/react-hooks";

We are importing the useMutation hook from react-apollo.

+ const [insertTodo, { loading, error }] = useMutation(INSERT_TODO);
const submit = () => {
setText('');
+ insertTodo({
+ variables: { text, isPublic },
+ });
};
return (
<View style={styles.inputContainer}>
<View style={styles.textboxContainer}>
<TextInput
style={styles.textbox}
editable = {true}
onChangeText = {setText}
value = {text}
/>
</View>
<View style={styles.buttonContainer}>
<TouchableOpacity style={styles.button} onPress={submit} disabled={text === ''}>
<Text style={styles.buttonText}> Add </Text>
</TouchableOpacity>
</View>
</View>
);

The useMutation hook defined above, accepts a GraphQL mutation and returns an array of two elements. The first element is a function (here insertTodo) that executes the given mutation on the GraphQL server. The second element is an object that contains the metadata of the GraphQL execution (data, error, loading). You can read more about useMutation here.

The insertTodo function optionally takes variables, optimisticResponse, refetchQueries, and update; You are going to make use of the update function later. As you see above, we call insertTodo above with variables. These are query variables for the given GraphQL mutation.

We are passing the insertTodo function to our Button's onPress handler. We are also passing the query variables that is text and isPublic to this mutate function so that our mutation is called with those variables. text is the value of the input box while isPublic, which is the type of the todo, is taken from props.

The mutation has been integrated and the new todos will be inserted into the database. But the UI doesn't know that a new todo has been added. We need a way to tell Apollo Client to update the query for the list of todos.

The update function comes in handy to update the cache for this mutation. It comes with utility functions such as readQuery and writeQuery that helps in reading from and writing to the cache.

Let's implement update for the above mutation.

We pass the update function to the mutation options while calling insertTodo.

insertTodo({
variables: { text, isPublic },
+ update: updateCache
});

We need to fetch the current list of todos from the cache. So let's import the query that we used in the previous steps.

import {FETCH_TODOS} from './Todos';

Let's define the updateCache function to read and write to cache..

+ const updateCache = (client, {data: {insert_todos}}) => {
+ const data = client.readQuery({
+ query: FETCH_TODOS,
+ variables: {
+ isPublic,
+ }
+ });
+ const newTodo = insert_todos.returning[0];
+ const newData = {
+ todos: [ newTodo, ...data.todos]
+ }
+ client.writeQuery({
+ query: FETCH_TODOS,
+ variables: {
+ isPublic,
+ },
+ data: newData
+ });
+ }

Let's dissect what's happening in this code snippet.

Our goals were simple:

  • Make a mutation to insert the new todo in the database.
  • Once the mutation is done, we need to update the cache to update the UI.

The update function is used to update the cache after a mutation occurs. It receives the result of the mutation (data) and the current cache (store) as arguments. You will then use these arguments to manage your cache so that the UI will be up to date.

client.readQuery

Unlike client.query, readQuery will never make a request to your GraphQL server. It will always read from the cache. So we make a read request to the cache to get the current list of todos.

client.writeQuery

We have already done the mutation to the graphql server using the mutate function. Our goal was to update the UI. This is where writeQuery comes to the rescue. writeQuery will allow you to change data in your local cache, but it is important to remember that they will not change any data on your server (exactly what we need).

Any subscriber to the Apollo Client store will instantly see this update and render new UI accordingly.

We concatenate our new todo from our mutation with the list of existing todos and write the query back to the cache with cache.writeQuery

Now, the Todos component using the useQuery hook will get the updated todo list as it is automatically subscribed to the store.

Great! That was actually easy :)