DEV Community

Abhay Singh Kathayat
Abhay Singh Kathayat

Posted on

Using Apollo Client for GraphQL Data Management in React

GraphQL with Apollo Client in React

Apollo Client is a popular library that enables you to interact with GraphQL APIs in a more efficient and declarative way. It simplifies data fetching, caching, and state management for React applications. With Apollo Client, you can easily send GraphQL queries and mutations to a GraphQL server and manage the data in your app.

Apollo Client works seamlessly with GraphQL, providing a powerful set of tools to manage data fetching, caching, error handling, and more. Below, we'll explore how to integrate Apollo Client with a React application, perform GraphQL operations, and manage state.


1. What is GraphQL?

GraphQL is a query language for APIs and a runtime for executing those queries with your data. It allows you to request only the data you need and get responses in a predictable structure.

Unlike REST, where you make multiple requests to different endpoints for various pieces of data, GraphQL allows you to send a single query that can retrieve multiple types of data from different sources in one go.


2. Installing Apollo Client

To use Apollo Client with React, you'll need to install the necessary dependencies. First, install Apollo Client and GraphQL:

npm install @apollo/client graphql
Enter fullscreen mode Exit fullscreen mode

3. Setting Up Apollo Client

To set up Apollo Client, you'll need to create an Apollo Client instance and connect it to a GraphQL endpoint. You'll also need to wrap your React app with the ApolloProvider component to make the Apollo Client instance available throughout the app.

import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloProvider, InMemoryCache } from '@apollo/client';
import App from './App';

// Create an Apollo Client instance
const client = new ApolloClient({
  uri: 'https://your-graphql-endpoint.com/graphql', // Your GraphQL endpoint
  cache: new InMemoryCache(), // Apollo Client's cache implementation
});

// Wrap your React app with ApolloProvider and pass the client
ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById('root')
);
Enter fullscreen mode Exit fullscreen mode
  • Apollo Client is created with the uri (the URL of your GraphQL server) and a cache (which uses InMemoryCache to store and manage cached data).

4. Making GraphQL Queries with Apollo Client

Apollo Client makes it easy to execute GraphQL queries in React using the useQuery hook. The hook returns an object with properties like data, loading, and error.

Here’s an example of how to use useQuery to fetch data from a GraphQL server.

import React from 'react';
import { useQuery, gql } from '@apollo/client';

// Define a GraphQL query
const GET_BOOKS_QUERY = gql`
  query GetBooks {
    books {
      id
      title
      author
    }
  }
`;

const BooksList = () => {
  // Execute the query using useQuery hook
  const { loading, error, data } = useQuery(GET_BOOKS_QUERY);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <h1>Books List</h1>
      <ul>
        {data.books.map((book) => (
          <li key={book.id}>
            {book.title} by {book.author}
          </li>
        ))}
      </ul>
    </div>
  );
};

export default BooksList;
Enter fullscreen mode Exit fullscreen mode
  • gql: A template literal provided by Apollo Client to define GraphQL queries or mutations.
  • useQuery: A hook provided by Apollo Client that executes the specified query and returns the data, loading, and error states.

5. Making GraphQL Mutations with Apollo Client

In addition to fetching data, Apollo Client also provides the ability to send GraphQL mutations using the useMutation hook. Mutations are used to modify data on the server (e.g., creating, updating, or deleting records).

Here’s an example of using useMutation to add a new book.

import React, { useState } from 'react';
import { useMutation, gql } from '@apollo/client';

// Define a GraphQL mutation
const ADD_BOOK_MUTATION = gql`
  mutation AddBook($title: String!, $author: String!) {
    addBook(title: $title, author: $author) {
      id
      title
      author
    }
  }
`;

const AddBook = () => {
  const [title, setTitle] = useState('');
  const [author, setAuthor] = useState('');

  const [addBook, { loading, error }] = useMutation(ADD_BOOK_MUTATION, {
    variables: { title, author },
    onCompleted: () => {
      setTitle('');
      setAuthor('');
    },
  });

  const handleSubmit = (e) => {
    e.preventDefault();
    addBook();
  };

  return (
    <div>
      <h2>Add a New Book</h2>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          placeholder="Title"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
        />
        <input
          type="text"
          placeholder="Author"
          value={author}
          onChange={(e) => setAuthor(e.target.value)}
        />
        <button type="submit" disabled={loading}>
          {loading ? 'Adding...' : 'Add Book'}
        </button>
      </form>
      {error && <div>Error: {error.message}</div>}
    </div>
  );
};

export default AddBook;
Enter fullscreen mode Exit fullscreen mode
  • useMutation: A hook for sending GraphQL mutations to the server. It takes the mutation and optionally an object with variables and options (like onCompleted or onError).
  • Variables: You can pass dynamic variables to mutations to make them more flexible (like title and author in the example).

6. Caching with Apollo Client

Apollo Client uses an in-memory cache to store the results of your queries. This means that once data is fetched, it is cached, and subsequent requests for the same data are served from the cache, improving performance.

For instance, if the user visits the same page again, the data will be loaded instantly from the cache.

To enable cache updates after a mutation, you can use refetchQueries or update options:

const [addBook] = useMutation(ADD_BOOK_MUTATION, {
  variables: { title, author },
  refetchQueries: [{ query: GET_BOOKS_QUERY }],  // Re-fetch books after mutation
});
Enter fullscreen mode Exit fullscreen mode

7. Error Handling and Optimistic UI

Apollo Client supports optimistic UI updates, where you can immediately update the UI to reflect the changes even before the server responds.

Example of using optimisticResponse for mutations:

const [addBook] = useMutation(ADD_BOOK_MUTATION, {
  optimisticResponse: {
    __typename: 'Mutation',
    addBook: {
      __typename: 'Book',
      id: 'temp-id',
      title: 'New Book',
      author: 'Unknown',
    },
  },
  update(cache, { data: { addBook } }) {
    const { books } = cache.readQuery({ query: GET_BOOKS_QUERY });
    cache.writeQuery({
      query: GET_BOOKS_QUERY,
      data: { books: books.concat([addBook]) },
    });
  },
});
Enter fullscreen mode Exit fullscreen mode
  • Optimistic Response: Apollo Client immediately updates the UI with the expected response, improving the user experience.
  • Cache Update: After the mutation completes, you can update the cache manually to ensure it reflects the new data.

8. Conclusion

Apollo Client simplifies working with GraphQL in React applications by providing powerful tools for querying, mutating, caching, and managing data. With the use of hooks like useQuery and useMutation, Apollo Client integrates seamlessly into functional React components and helps maintain an efficient, declarative approach to data management.


Top comments (0)