In Part 1, I explored how to update the Apollo Client cache using RefetchQueries. However, as mentioned in the article, this approach results in unnecessary network requests. In this article, I will demonstrate how to use a GraphQL Query to read and rewrite the cache.
Using GraphQL Query
The official Apollo Client documentation presents various methods for reading and writing to the cache.
Among these, the GraphQL query is a method for both reading cache and writing new cache data.
readQuery
The readQuery
method is a straightforward way to execute a GraphQL query directly on your cache. As the documentation states:
The readQuery method enables you to execute a GraphQL query directly on your cache.
In essence, readQuery
allows you to retrieve data from the cache with ease.
Below is an example from the documentation on how to use readQuery:
const READ_TODO = gql` //defining the query
query ReadTodo($id: ID!) {
todo(id: $id) {
id
text
completed
}
}
`;
// Fetch the cached to-do item with ID 5
const { todo } = client.readQuery({
query: READ_TODO,
// Provide any required variables in this object.
// Variables of mismatched types will return `null`.
variables: {
id: 5,
},
});
writeQuery
The writeQuery
is also a self-explanatory method, according to the documentation:
The writeQuery method enables you to write data to your cache in a shape that matches a GraphQL query. It resembles readQuery, except that it requires a data option.
Using writeQuery
, you can update the cache to ensure that the UI remains synchronized with the data.
Below is the example use case of writeQuery.
const completeTask = async (taskId) => {
// Optimistically update the cache
client.writeQuery({
query: GET_TASKS_QUERY,
data: {
tasks: tasks.map(task =>
task.id === taskId ? { ...task, completed: true } : task
),
},
});
// Send the mutation to the server
try {
await client.mutate({
mutation: COMPLETE_TASK_MUTATION,
variables: { taskId },
});
} catch (error) {
// Rollback the optimistic update if the mutation fails
client.writeQuery({
query: GET_TASKS_QUERY,
data: { tasks },
});
}
};
In the code example above, when a user completes a task in a to-do list, it optimistically updates the cache using writeQuery, which enables the app to update the UI accordingly. If there is an error in the process of completing the task, the cache is updated again to reflect the error state.
Update function
In my scenario, the cache needs to be modified immediately after a mutation occurs. Therefore, I provide an update
function to useMutationm in which I use both readQuery
and writeQuery
, to manually apply changes to my cached data.
Here is the code.
const [registerPiece] = useMutation<RegisterPieceMutationData>(REGISTER_PIECE_MUTATION, {
update: (cache, { data }) => {
if (data) {
const existingData: WardrobeQueryData | null = cache.readQuery({
query: GET_WARDROBE_QUERY,
});
if (existingData) {
cache.writeQuery({
query: GET_WARDROBE_QUERY,
data: { piece: [data.piece, ...existingData.piece] },
});
}
}
},
As an option for REGISTER_PIECE_MUTATION
, I put update function.
The update function is passed a **cache object **that represents the Apollo Client cache. This object provides access to readQuery
/writeQuery
that I mentioned above. Additionally, it is passed data that contains the result of the mutation, which you can use to update the cache with writeQuery
method.
if (data) {
const existingData: WardrobeQueryData | null = cache.readQuery({
query: GET_WARDROBE_QUERY,
});
In the code snippet above, if data is present, the readQuery
method is triggered, and the result is stored in existingData.
if (existingData) {
cache.writeQuery({
query: GET_WARDROBE_QUERY,
data: { piece: [data.piece, ...existingData.piece] },
});
}
Then, if existing data is not null or undefined, it will execute writeQuery
method to rewrite the cache.
Right after the registration of the piece, a user is not required to refresh the page to see the newly registered piece now.
Conclusion
Although the example in this article demonstrated a straightforward use case for readQuery
and writeQuery
, updating the cache can be a bit daunting. If not done correctly, users may encounter confusing or incorrect UI results. Other than GraphQL Queries, there are also GraphQL fragments and the modify method for updating existing cache data or inserting new cache data. I will explore the GraphQL fragment next when I implement update piece detail feature.
I hope this article has been helpful for those who are just starting out with Apollo Client, like myself :)!!
Top comments (0)