Apollo client and React

Apollo client and React

“🚀 A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server” — Apollo Client github repository


Why do we need a GraphQL client?

As GraphQL backends expose their API over a single HTTP endpoint, we could just use fetch to interact with it. The problem is this doesn’t scale well because we would need to reimplement backend agnostic features on every project, such as caching data, updating the local cache after a mutation, UI framework integration, and more!

A GraphQL client should have those kinds of functionalities so that you don’t have to reimplement these behaviors yourself. Instead, you can completely focus on your application domain and on implementing the specific requirements of your app.

As we should expect, there is a multitude of GraphQL clients to choose from, in this article we’ll go over Apollo Client.

Why Apollo Client?

“Apollo Client is a complete state management library for JavaScript apps. Simply write a GraphQL query, and Apollo Client will take care of requesting and caching your data, as well as updating your UI.” — Apollo Client docs

Apollo provides a lightweight and flexible approach that works in any environment. Many tasks such as keeping the local cache consistent can also be achieved with Apollo Client, but require more manual work and bookkeeping.

Since Apollo Client is framework agnostic, it’s a great option to learn and use in your applications. Everything you learn can be used on React, Vue, and even on native apps!

In this article, we’ll see how to use Apollo Client with React.

Setup

First, we need to add the required dependencies to use Apollo Client on a React application, using either npm or yarn.

Dependencies required to use Apollo Client on a React app:

npm install --save react-apollo graphql graphql-tag apollo-cache-inmemory apollo-client apollo-link-http

Once we’ve successfully installed the dependencies, we have to set up the Apollo Client. To do so, we only need to let it know our GraphQL endpoint. Note that we are also using an in-memory cache, we’ll cover this later.

Basic Apollo Client configuration:

import ApolloClient from "apollo-client";
import { HttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";
const cache = new InMemoryCache();
const link = new HttpLink({ uri: process.env.GRAPHQL_API_URL });
export const apolloClient = new ApolloClient({
name: "our-awesome-client",
link,
cache,
});

Now that we’ve created our client, we need to wrap our application in the ApolloProvider tag, so that our app has access to our newly created client.

import React from "react";
import ReactDOM from "react-dom";
import { ApolloProvider } from "react-apollo";
import App from "./containers/App";
import { apolloClient } from "./graphQL/client";
ReactDOM.render(
<ApolloProvider client={apolloClient}>
<App />
</ApolloProvider>,
document.getElementById("mount")
);

As you should know by now (if you don’t, check out this awesome article), in GraphQL we use Queries to retrieve data and Mutations to mutate data.

In our React app, there are two ways to do either of them, by using components or hooks. We’ll cover the latter as they are much cleaner and more pleasant to work with.

Queries

Let’s say we want to get the id and name of all the Users on our imaginary GraphQL backend. This is easily done by writing the following query.

Now, we can use this query to actually fetch some users by using the useQuery hook. In order to run a query, we need to call useQuery and pass a GraphQL query string to it. This hook returns a result object that contains the following properties:

const FETCH_USERS = gql`{
users {
id
name
}
}`;
  • loading: whether the request is in flight or not.
  • data: the result of your GraphQL query (defaults to undefined).
  • error: a runtime error with graphQLErrors and networkError properties.
  • …and more.

Usage example of useQuery:

import { useQuery } from "@apollo/react-hooks";
import FETCH_USERS from "../graphQL/queries/fetchUsers";
const Component = () => {
const { loading, data, error } = useQuery(FETCH_USERS);
if (loading) return "Loading...";
if (error) return "Oops :(";
return (
<li>
{data.map(({ id, name }) => (
<ul key={id}>{name}</ul>
))}
</li>
);
};

Mutations

As an example, we may want to create a Post with a title and a body. To do this, we must write a mutation:

mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
post {
title
body
id
createdAt
}
}
}

Here, CreatPostInput is a GraphQL type defined in our backend, that has title and body fields.

To use this mutation we can use the useMutation hook. This hook returns an array where this first item is the mutation itself and the second item is pretty similar to the one returned by useQuery.

Usage example of useMutation:

import { useMutation } from "@apollo/react-hooks";
import CREATE_POST from "../graphQL/queries/createPost";
const Component = () => {
const [createPost, { loading }] = useMutation(CREATE_POST);
return (
<form
onSubmit={(ev) => {
ev.preventDefault();
const { title, body } = ev.target.elements;
createPost({ variables: { title, body } });
}}
>
<label htmlFor="title">Title</label>
<input name="title" id="title" />
<label htmlFor="body">Body</label>
<textarea name="body" id="body" />
<button type="submit">{loading ? "Loading..." : "Submit"}</button>
</form>
);
};

Apollo Cache

“Apollo Client stores the results of its GraphQL queries in a normalized, in-memory cache. This enables your client to respond to future queries for the same data without sending unnecessary network requests.” — Apollo Client docs

What does this mean? It means that we can use this in-memory cache as our global state, no need to use Redux or Context!

Apollo exposes a handful of functions to read and write the cache. To keep this post short we won’t cover it, but you can read about it in Apollo’s documentation.


To sum up, by using Apollo we get a way to use GraphQL queries and mutations and an included global state manager! The latter was the main selling point for me.

Look at an example project here!