Subscribe

DevelopmentArticle

GraphQL in React with Apollo Client: Queries, Mutations and Uploads

Ask for exactly the data a screen needs, in one request, and let a normalized cache keep the interface in sync. A practical walkthrough of Apollo Client in React.

Published By Aviox Blogs Engineering · 6 min read
On this page
  1. Why GraphQL
  2. What Apollo Client adds
  3. Connecting the client
  4. Reading data with useQuery

Why GraphQL

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. A client describes the shape of the data it wants and receives exactly that — nothing more, nothing less — in a predictable structure.

Queries can follow references between resources, so data that a typical REST API would spread across several URLs arrives in a single request. Because the client controls what it fetches, applications stay fast and stable as screens evolve.

What Apollo Client adds

Apollo Client is a fully featured JavaScript GraphQL client. It sends queries and mutations, caches results in a normalized in-memory store, tracks loading and error states, and integrates with React, Angular and Vue. Its cache also doubles as a home for local state, kept in step with the server.

Install it alongside the reference graphql package:

npm install @apollo/client graphql
@apollo/client
Querying and mutating data, a normalized cache for local and remote data, subscriptions for real-time updates, error handling and retries, and links for customizing requests.
graphql
The reference implementation used to parse and validate queries. On the server it defines schemas and resolvers; on the client it parses the documents you send.

Connecting the client

Create one client for the application — pointing an HttpLink at your GraphQL endpoint and giving it a cache — then provide it to the component tree:

import { createRoot } from "react-dom/client";
import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client";
import { ApolloProvider } from "@apollo/client/react";
import App from "./App";

const client = new ApolloClient({
  link: new HttpLink({ uri: "https://api.example.com/graphql" }),
  cache: new InMemoryCache(),
});

createRoot(document.getElementById("root")).render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
);
src/main.jsx

Version note

Since Apollo Client 4, React APIs such as ApolloProvider, useQuery and useMutation are imported from @apollo/client/react, and the endpoint is configured through a link rather than a uri shortcut. Older projects on version 3 import everything from @apollo/client.

Reading data with useQuery

Define the query with gql. Its structure mirrors the data you expect back — one of GraphQL’s defining features:

import { gql } from "@apollo/client";

export const GET_USERS = gql\`
  query GetUsers {
    users {
      id
      name
      email
    }
  }
\`;
src/queries.js

Arguments narrow the result. To fetch only the name and email of user 123, ask for exactly that:

query GetUser {
  user(id: 123) {
    name
    email
  }
}

The useQuery hook runs the query, re-renders as its state changes, and serves repeat requests from the cache:

import { useQuery } from "@apollo/client/react";
import { GET_USERS } from "./queries";

export default function UserList() {
  const { loading, error, data } = useQuery(GET_USERS);

  if (loading) return <p>Loading…</p>;
  if (error) return <p role="alert">Couldn’t load users: {error.message}</p>;

  return (
    <ul>
      {data.users.map((user) => (
        <li key={user.id}>
          {user.name} ({user.email})
        </li>
      ))}
    </ul>
  );
}
src/UserList.jsx

Keep reading — it’s free

The remaining 3 min of this story is for Dispatch subscribers. Subscribing takes one field, and the whole story opens right here.

Originally published at Aviox Blogs engineering handbook.

Written by Aviox Blogs Engineering

Field notes, deployment guides and research from the engineers who build web, cloud and mobile products at Aviox Blogs.