Apollo / GraphCool Optimistic UI for Delete Mutations

James Jung
3 min readJul 3, 2017

A lot of the examples I see online are for Optimistic UI updates for adding items to a list. I want to share another real world example of how we use Optimistic UI updates in Metacall to immediately remove Cards from the CardDrawer.

I have a removeFromDrawer mutation that takes in drawerId and cardsId. So in my event handler to remove cards, I simply call the mutation like so.

handleDrawerRemoveCard(id) {
const variables = {
drawerId: this.props.drawerId,
cardId: id
}
this.props.removeFromDrawer({
variables
})
}

When I go into the CardDrawer and click on the remove button, there is a very noticeable delay before the list item is removed. Apollo Client provides a way for the client to update immediately through Optimistic UI.

In order for this to work we need to add two more options to the mutation: update and optimisticResponse.

Essentially, we are mocking out the response we get back from the server and updating the apollo store manually immediately instead of waiting for the response. Therefore, we add the update field like so:

handleDrawerRemoveCard(id) {
const variables = {
drawerId: this.props.drawerId,
cardId: id
}
this.props.removeFromDrawer({
variables,
update: : (store, {data: {removeFromCardDrawer}}) => {
const data = store.readQuery({
query: drawerQuery,
variables: { drawerId: this.props.drawerId}
})
data.Drawer.cards = data.Drawer.cards.filter(card => card.id !== removeFromCardDrawer.cardsCard.id)
store.writeQuery({query: drawerQuery, data})
}
})
}

the update takes in the apollo store and the data we want to manipulate. To get the current state of the Drawer, we call the readQuery method on the store with the proper options added on. If we console log data and removeFromCardDrawer we will see the below:

So all we have to do in update is to update the Drawer.cards Array where it will remove the card with the id from the removeFromCardDrawer.cardsCard.id. Therefore we just filter through the cards Array where the cards do not have the id from the removeFromCardDrawer mutation. Once we update the Array we can then write it to the store via store.writeQuery.

However, this isn’t enough to make the experience instant. We must now add the optimisticResponse to the mutation.

The apollo docs explains what happens with the update and optimisticResponse very well.

If you provide an optimisticResponse option to the mutation then the update function will be run twice. Once immediately after you call client.mutate with the data from optimisticResponse. After the mutation successfully executes against the server the changes made in the first call to update will be rolled back and update will be called with the actual data returned by the mutation and not just the optimistic response.

So in order for our handler to support Optimistic UI, we add the optimisticResponse like this:

handleDrawerRemoveCard (id) {
const variables = {
drawerId: this.props.drawerId,
cardId: id
}
this.props.removeFromDrawer({
variables,
update: (store, {data: {removeFromCardDrawer}}) => {
const data = store.readQuery({
query: drawerQuery,
variables: { drawerId: this.props.drawerId}
})
data.Drawer.cards = data.Drawer.cards.filter(card => card.id !== removeFromCardDrawer.cardsCard.id)
store.writeQuery({query: drawerQuery, data})
},
optimisticResponse: {
removeFromCardDrawer: {
cardsCard: {
id
},
__typename: 'RemoveFromCardDrawerPayload',
},
}
})
}

Right now I am sure you are thinking how the hell do I know what the response looks like? Apollo store is built on top of Redux so I just look at the Redux DevTools in Chrome! For setup instructions and overview, click here.

When I execute the mutation, I should receive something called APOLLO_MUTATION_RESULT. It is in this action that I can see the response in the form of data.

Take a look at what is in my optimisticResponse field and you’ll see that it is the exact same as what was returned from GraphCool.

And there you have it. It was a bit overwhelming for me at first but I hope I broke it down into simple and understandable steps for you to implement Optimistic UI in your own application.

--

--