Real Time GraphQL Mutations — Using Apollo Client, React and Optimistic UI

Taking your app UX to the next level isn’t an easy task, however choosing the right tools can help you deliver a brilliant experience to your users.

A long short story — I’ve always been interested in learning new technologies to improve the websites I developed for a better UI/UX. It seems to be easy to think like that, but it’s actually very hard and sometimes frustration to bring the most value to your users.

Almost an year ago I’ve started a project called Askable as a side project at the company I’m currently working for. Since then it started to get traction and it became a very promising project that could be turned out into a company with very hard stakes and challenges to overcome everyday. I still remember the day I was creating the booking form (Basically 5 different pages with loads of options and a Save button in every page) and the head of product Dre Zhou came to me saying that he wanted that form to be “Real Time”.

I simply told him: “You know that’s not an easy task, right?” He then replied: “I know, but I know you can do it!”. I did it.

In this article I’ll show you how I achieved such a thing.


Choose your stack well

Take your time. There are a lot of tools available to help us create amazing experiences. Two years ago I was bored and frustrated with the technology I was using and then I decided to step up and study React and React Native. This was by far one of the best decisions I’ve made in my professional life. One year later I was building amazing apps and websites with React and Redux, but got overwhelmed with the amount of code I had to put up. I then decided to step up again and study GraphQL (Mainly because of an article from Peggy Rayzis). Another great professional decision.

The beauty of technology comes when you start connecting the all the dots to create amazing products.

Tools like Apollo and React are awesome and you should check them out.

Anyway, enough talking about me and how I became who I”m today. Let’s go to the fun part…


Real-time

How can you achieve an experience that products like Medium or Google Docs bring to you? Imagine yourself in a situation where you need to save data while the user is typing. That itself bring lots of questions:

  • Can my server process HTTP requests in real-time?
  • Will it crash my server?
  • Should I make a call every time my state changes?
  • What happens with the data the server returns?
  • But, how?

The answer is GraphQL, Apollo Client and Optimistic UI.

Optimistic UI stands for an operation that fakes your final data and update your state until your network responds back from your server.


Final Goal

Askable Booking Process (Website in production using React and GraphQL)

Notice in this example the little status toggle close to the “Next” button. It’s reflecting the real-time changes on the database. Differently to what most people might think, this page doesn’t save the data on the “Next” or “Save & Close” button. In fact, those buttons don’t do anything special, they just redirect the user to a different page.

Every change on this page triggers a mutation called updateBooking, and every piece of data is connected to a field returned from a query.
These are the steps to get this process up and running:

  1. Setting up your Query
  2. Setting up your Mutation
  3. Connect your Query and Mutation to your component
  4. Make your UI fields rely on your query
I’ve included all the fields we are using in production to make this process feel as close as it is in production. (You probably don’t need this level of complexity on your code)

Setting up your Query

query FetchBookingsById($id: ID) {
bookingByID(id: $id) {
_id
config {
type
}
}
}

Settings up your Mutation

mutation updateBooking($booking_id: ID!, $booking: BookingInput!) {
updateBooking(booking_id: $booking_id, booking: $booking) {
_id
config {
type
}
}
}

Notice that the returned fields from my mutation are exactly the same from my FetchBookingById query. This is intentional and VERY important to make our Optimistic UI to work. (You can use Fragments if you want to make sure both files are in sync)

Connect your Query and Mutation to your component

import { graphql, compose } from 'react-apollo';
import fetchBookingById from 'src/queries/booking/fetchBookingById';
import updateBookingDetails from 'src/mutations/booking/updateBookingDetails';
... your component code ...
const bookingDataContainer = graphql(fetchBookingById, {
name: 'bookingData',
options: () => ({
variables: {
id: booking_id
}
})
});
const updateBookingContainer = graphql(updateBookingDetails, {
props: ({ mutate }) => ({
updateBooking: (booking_id, booking) => mutate({
variables: { booking_id, booking },
refetchQueries: [{
query: fetchBookingById,
variables: { id: booking_id },
}],
optimisticResponse: {
updateBooking: {
_id: booking_id,
config: {
type: booking.config.type,
__typename: 'BookingConfig'
},
__typename: 'Booking'
}
}
}),
})
});
export default compose(
bookingDataContainer,
updateBookingContainer
)(CreateBookingStepBookingDetails);

Make your UI fields rely on your query

renderSessionTypesContainer() {
return (
<div
key="sessionTypesContainer"
className="sessionTypesContainer bookingFormAccordion"
>
<RadioButton
name="sessionTypesGroup"
onChange={(value) => {
this.updateBooking({
booking: {
...this.state.booking,
config: {
...this.state.booking.config,
type: parseInt(value, 10)
}
}
});
}}
value={this.props.bookingData.bookingByID.config.type}
values={bookingUtils.sessionTypes()}
/>
</div>
);
}

Notice that the value of our component that will render the “Session Times” on our UI is coming from our props.

Breaking it down

So let’s break down this whole code to understand how each part is playing well with each other.

  1. The page is loaded with a bunch of pre-filled fields. We call them Default Valid fields (Which you can read more about it on our post here)
  2. The user changes the Session Time (which happens on the GIF above) from 1 on 1 interviews to Focus Group.
  3. We update our local state to change the field booking.config.session.type
  4. We call our mutation updateBooking sending along our updated “booking” (Coming from this.state)
  5. Apollo identifies that we are using an Optimistic UI on the mutation, so it returns straight away what we believe it’s going to be the return from our network
  6. We update our UI based on our new props (notice that we connected our mutation to our component via compose)
  7. Once the network request comes back from our server, it will update the component again, as it will receive new props.

Advantages of this approach

We’ve been getting lots of real good feedback from our users after we adopted this approach of using Optimistic UI with React and Apollo to update UI components. In fact, we’ve seen an increase of 20% on the number of returning clients that started a booking and finished where they left off in the past. This also improved significantly the level of trust we’re building up with clients as they know their information is always saved securely and in real-time.

We’ve been running React and GraphQL together in production for a while already, so feel free to get in touch with me if you have any question. Feedbacks are also very welcome.

Like what you read? Give Francisco Varisco a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.