Apollo Client

Apollo Client is the client-side counterpart to Apollo Server. We use it for managing queries and mutations from the frontend to our Apollo GraphQL server. It is specifically designed to work with React.

We will be working with the schema we defined when working on the server

Initializing the client

We initialise the client and set-up in memory caching to reduce network requests:

const client = new ApolloClient({
  uri: "http://localhost:4000",
  cache: new InMemoryCache(),
});

The uri property must match the location of our Apollo server.

Utilising the provider

Apollo provides a top level application context that we can wrap our React app in. This will provide access to the client object from anywhere within the app, eg:

ReactDOM.render(
  <ApolloProvider client={client}>
    <GlobalStyles />
    <Pages />
  </ApolloProvider>,
  document.getElementById("root")
);

Running a query

Queries as entry points

From the client point of view, the queries in the schema are entry points. Although the queries exist in the schema, this alone is not sufficient for them to be entry points. Remember a schema is just a specification or contract between the frontend and the backend, it is not itself executable code.

Therefore, for each query in the schema we must write a frontend implementation. We do this with query constants. The frontend implementation has a backend analogue: the resolver that is invoked when the frontend issues a query. The schema standardises this relationship so that every query on the client must have a corresponding resolver on the backend.

Query constants

To run a query against our server we must define a query contant first. We use a gql literal again:

import { gql } from "@apollo/client";
const TRACKS = gql`
  query GetTracks {
    tracksForHome {
      id
      title
      thumbnail
      length
      modulesCount
      author {
        name
        photo
      }
    }
  }
`;

The convention is to name the query constant in ALL_CAPS.

Note that the name of the query on the client doesn’t have to match the query type defined in the schema (there is no GetTracks in the schema), this is just a client-side designator. However it should reference the schema on the second line (tracksForHome).

useQuery hook

The useQuery hook provides a straightforward wrapper for sending queries and receiving data back from the server.

When a component renders, useQuery returns an object from the Apollo Client that contains loading, error, and data properties.

const { loading, error, data } = useQuery(TRACKS);

const Tracks = () => {
  const { loading, error, data } = useQuery(TRACKS);

  if (loading) return "Loading...";

  if (error) return `Error! ${error.message}`;

  return <Layout grid>{JSON.stringify(data)}</Layout>;
};
  • We destructure the loading, error, data variables that are returned from the hook
  • We pass in our query constant as an argument.
  • In the example we just render the serialized data but we could of course pass the data as a prop and map through it in an embedded child component.