GraphQL On The Front-End (React And Apollo) — Smashing Magazine

GraphQL On The Front-End (React And Apollo)

About The Author

David currently writes frontend code for canaryng.com, and is constantly working to make the web more accessible to everyone.

Interests apart from coding include …

More about
David ↬

Quick summary ↬

Within the last decade, technologies like GraphQL have changed how we build web apps and how they communicate with each other. GraphQL provides certain benefits over REST APIs — let’s find out what they are.

One of the main benefits of GraphQL is the client’s ability to request what they need from the server and receive that data exactly and predictably. Without much effort, one can easily pull nested data by just adding more properties to our queries instead of adding multiple endpoints. This prevents issues like over-fetching that can impact performance.

Usually, to handle GraphQL on the client-side, we make use of the Apollo Client. It allows developers to define, handle, and make queries/mutations available within our application. It can also act as a state management tool with your client-side application.

In this article, we’re going to learn how to handle real-time updates on the client-side using GraphQL. We’ll be learning how to do this with GraphQL Features like Cache Update, Subscriptions, and Optimistic UI. We’ll also be touching on how to use Apollo as a state-management tool, possibly replacing redux. Plus, we’ll look at how to create usuable GraphQL queries with Fragments, and how to use Apollo directives to write more complex queries.

Before we begin, let’s just go through installation and setting up our project. Let’s get right into the code. To create a React app, make sure you have Node.js installed on your computer. If you haven’t built a React app before, you can check to see if you have Node.js installed by typing the following into your terminal:

If not, just go to the Node.js website to download the latest version.

Once that’s done, we can get started with our React app by running this command:

Once, that’s done we’ll install Apollo using:

Then, we navigate into our project folder on the terminal:

Or better still, you could just go on and clone the repo. The repo contains both the client-side and server, so we have some other dependencies that’s needed.

We would install those dependencies by running:

Just before we start, this is the repo containing the code demonstrating everything under Real-time update on GraphQL, using Apollo as a state management tool, Fragments, and Apollo directives. Also, here’s the repo containing the code demonstrating subscription on the the client-side.

More after jump! Continue reading below ↓

Meet Smashing Online Workshops on front-end & UX, with practical takeaways, live sessions, video recordings and a friendly Q&A. On design systems, CSS/JS and UX. With Carie Fisher, Stefan Baumgartner and so many others.

Real-time Update On GraphQL

The ability to create a real-time update on the client-side helps improve the user experience of the site, making everything seem smoother. Just imagine a situation where a user adds a new item by filling a form, and that item updates instantly by been added to the list of items on the same page. Although, this real-time update could sync with a server directly through subscriptions, or it might be manipulated on the frontend through things like Optimistic UI, or using the update function on the useMutation. So let’s get to the technical implementation. Here’s the repo containing the code demonstrating everything under Real-time update On Graphql, using Apollo as a state management tool, Fragments, and Apollo directives.

Updating the cache directly using update function on the useMutation

useMutations are imported directly from the @apollo/client library, and it helps us make mutations to the data on our server.

Usually, we can create mutations with Apollo using useMutations, but beyond that, what we’ll be doing is using the update function to update our apollo-client cache directly through useMutation.

In this sample below, we send queries to the server to get a list of pets using useQuery and make a mutation by having a form to add more pets to our server using useMutation. The problem we’ll have is that when a new pet is added to the server, it doesn’t get added to the list of pets(on the browser) immediately, unless the page is refreshed. This makes the user experience of this section of the app feel broken, especially since the list of pets and the form are on the same page.

Using update function in the useMutation hook allows us to directly update our cache by reading and writing our ALL_PETS. Immediately we hit the submit button, the data is added to the list of pets in the cache by altering ALL_PETS. This lets us update our client-side cache immediately with consistent data.

Subscriptions In GraphQL

Based on functionalities, subscription in GraphQL is similar to queries. The major difference is that while Queries is done just once, subscriptions are connected to the server, and automatically updates when there’s any change to that particular subscription. Here’s the repo containing the code demonstrating subscription on the the client-side.

First, we have to install:

Then we go to our index.js to import and use it.

Note: uri in the code block directly above is for our endpoint.

Then we go into our component and instead of query like we have above, we’ll use this subscription instead:

And instead of using useQuery, we would access our data using useSubscription.

Optimistic UI

Optimistic UI is a little different in the sense that it’s not syncing with the server, like a subscription. When we make a mutation, instead of waiting for another server request, it automatically uses the already inputted data to update the list of pets immediately. Then, once the original data from the server arrives, it will replace the optimistic response. This is also different from “Updating the cache directly using update function on the useMutation”, even though we are still going to update the cache in this process.

When the code above calls onSubmit, the Apollo Client cache stores an addPet object with the field values specified in optimisticResponse. However, it does not overwrite the main cached pets(ALL_PETS) with the same cache identifier. Instead, it stores a separate, optimistic version of the object. This ensures that our cached data remains accurate if our optimisticResponse is wrong.

Apollo Client notifies all active queries that include the modified pets(ALL_PETS). Those queries automatically update, and their associated components re-render to show our optimistic data. This doesn’t require any network requests, so it displays instantly to the user.

Eventually, our server responds to the mutation’s actual to get the correct addPet object. Then, Apollo Client cache discards our optimistic version of the addPet object. It also overwrites the cached version with values returned from the server.

Apollo Client immediately notifies all affected queries again. The concerned components re-render, but if the server’s response matches our optimisticResponse, this is entire process is invisible to the user.

Using Apollo As A State Management Tool On The Client-side

When we think of state management tools or libraries concerning react, redux comes to mind. Interestingly, Apollo can also act as a management tool for our local state. Similar to what we’ve been doing with our API.

Client-side Schemas And Resolvers

To achieve this, we’ll have to write schemas on the client-side to define the type of data we want and how we want it to be structured. To do this, we’ll create Client.js where we’ll define the schemas and resolvers, after which, we’ll make it globally accessible in our project with the Apollo client.

For this example, I’ll be extending the User type that exists already to add height as an integer. The resolvers is also added to populate the height field in our schema.

We can then import the client into our index.js:

Within the component, it will use it just like this. We add @client to indicate that the query is from the client-side, and it should not try to pull it from the server.

So we’re pulling data from both the server and the client within the same query, and it’ll be accessible through the useQuery hook.

Fragments-Creating Reusable Queries

Sometimes we might need to pull the same query in different components. So instead of hardcoding it multiple times, we assign that query to some sort of variable, and use that variable instead.

In our component we just define the fragment as PetFields on Pet(which is the Type). That way we can just use it in both our query and mutation.

Apollo Directives

When making queries, we might want to have some conditionals that remove or include a field or fragment if a particular condition is fulfilled or not. The default directives include:

@skip: Indicates that a field/fragment should be skipped if a condition is fulfilled.

Here $name is a boolean that’s added as a variable when we are calling this query. Which is then used with @skip to determine when to display the field name. If true, it skips, and if falses it resolves that field.

@includes also work in a similar manner. If the condition is true, that field is resolved and added, and if it’s false, it’s not resolved.

We also have @deprecated that can be used in schemas to retire fields, where you can even add reasons.

We also have libraries that allow us to add even more directives, they could prove useful when building somewhat complicated stuff with GraphQL.

Tips And Tricks With Using GraphQL Lodash Inside Your Queries

GraphQL Lodash is a library that can help us a query in a more efficient way, more like an advanced form of the Apollo directives.

It can help you query your server in a way that returns data more neatly and compactly. For instance, you’re querying the title of films like this:

And it returns the title of movies as objects in an array.

But, when we use lodash’s map directive, when can sort of loop through the films array to have a single array with all the titles as direct children. We would send a query our server that looks like this:

You’ll get this response which one might consider relatively neater than the previous one.

Another one that proves useful is the is keyby directive. You can send a simple query like this:

Response:

Let’s use @_keyup directive in our query:

The response will look just like this:

So in this case each response has a key, that’s the name of the person.

In this article, we covered advanced topics to achieve real-time update of data using the update() function, subscription, and Optimistic UI. All in a bit to improve user experience.

We also touched upon using GraphQL to manage state on the client-side, and creating resuable queries with GrahQL fragments. The latter allows us to use the same queries in different components where it’s needed without having to repeat the entire thing every time.

In the end, we went through Apollo directives and Grahql Lodash to help us query our servers in a faster and better way. You can also check out Scott Moss’s tutorial if you’re looking to cover Graphql and react from scratch.

Smashing Editorial
(vf, yk, il)

This content was originally published here.