Connect GraphQL with React - 2 ways

Connect GraphQL with React - 2 ways

Learn how to connect GraphQL with react using Apollo Client and Axios

What is GraphQL?

GraphQL is a query language designed for APIs, as well as a server-side runtime for executing queries. It differs significantly from REST in that it allows clients to precisely define the data they need, which can minimize data over-fetching and under-fetching issues.

What is a Query?

In GraphQL, a "query" is used to fetch data. Unlike REST where you would typically retrieve data from a specific endpoint, GraphQL queries are sent to a single endpoint and are crafted to specify exactly what data is needed, no more, no less. This is one of the core features of GraphQL that eliminates the inefficiency of downloading unnecessary data.

What is a Mutation?

In GraphQL, a "mutation" is used to insert, update, or delete data. This is analogous to POST, PUT, DELETE in REST. Mutations ensure that you can manage your data effectively, providing clear patterns for client-server interaction.

Fetch and Mutate Data with Apollo Client

Install Apollo Client

npm install @apollo/client graphql

Connect Your React App with Apollo

In your main React file (usually index.js), import the necessary Apollo Client libraries to initialize the client and wrap your React app:

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

// Initialize Apollo Client
const client = new ApolloClient({
  uri: "YOUR_GRAPHQL_API_ENDPOINT",
  cache: new InMemoryCache(),
});

// Wrap your React app with ApolloProvider
ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById("root")
);
  • ApolloClient is the core mechanism for interacting with a GraphQL server, handling data fetching, caching, and state management of GraphQL queries.

  • InMemoryCache is a cache implementation used by Apollo Client to store and manage the results of GraphQL queries efficiently, enhancing performance by reusing data.

  • ApolloProvider is a React component that leverages React's Context API to provide the Apollo Client instance to all components within an application, enabling any component to access and operate GraphQL data.

Fetching Data with GraphQL in React

Step 1: Define a Query

query GetUsers {
  users {
    id
    name
    email
  }
}

Step 2: Use the Query

You can use the useQuery hook from Apollo Client to execute this query in your component:

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

const GET_USERS = gql`
  query GetUsers {
    users {
      id
      name
      email
    }
  }
`;

function Users() {
  const { loading, error, data } = useQuery(GET_USERS);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return data.users.map(({ id, name, email }) => (
    <div key={id}>
      <p>{`${name}: ${email}`}</p>
    </div>
  ));
}

export default Users;
  • useQuery is a React hook from Apollo Client used to execute a GraphQL query and manage the response lifecycle, including loading, error handling, and data retrieval.

  • loading is a boolean flag indicating whether the query is actively fetching data, useful for displaying loading indicators in your UI.

  • error contains an error object if an error occurred during the query, enabling error handling and user notifications in the UI.

  • data holds the actual data returned by the GraphQL query, structured as per your query, which you use to render results in your UI.

Adding Data with GraphQL Mutations

Step 1: Define a Mutation

mutation AddUser($name: String!, $email: String!) {
  addUser(name: $name, email: $email) {
    id
    name
    email
  }
}

Step 2: Use the Mutation

In React, you can use the useMutation hook from Apollo Client to handle this mutation.

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

const ADD_USER = gql`
  mutation AddUser($name: String!, $email: String!) {
    addUser(name: $name, email: $email) {
      id
      name
      email
    }
  }
`;

function AddUserForm() {
  let inputName, inputEmail;
  const [addUser, { data, loading, error }] = useMutation(ADD_USER);

  if (loading) return "Submitting...";
  if (error) return `Submission error! ${error.message}`;

  return (
    <div>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          addUser({
            variables: { name: inputName.value, email: inputEmail.value },
          });
          inputName.value = "";
          inputEmail.value = "";
        }}
      >
        <input
          ref={(node) => {
            inputName = node;
          }}
          placeholder="Name"
        />
        <input
          ref={(node) => {
            inputEmail = node;
          }}
          placeholder="Email"
        />
        <button type="submit">Add User</button>
      </form>
      {data && <p>Saved! User {data.addUser.name} created.</p>}
    </div>
  );
}

export default AddUserForm;
  • useMutation is a React hook from Apollo Client used for executing GraphQL mutations such as ADD_USER, managing the mutation lifecycle including state changes like loading, success, and error states.

  • addUser is the function returned by useMutation for invoking the ADD_USER mutation, allowing you to send the mutation to your GraphQL server with appropriate variables, such as user input data

Fetch and Mutate Data with Axios + React Query

Install Axios and React Query

npm install axios react-query

Fetching Data with Axios and React Query

To fetch data using Axios within React Query, you define a query using the useQuery hook, where the query function utilizes Axios to send a POST request to your GraphQL server. Here's an example setup:

import { useQuery } from "react-query";
import axios from "axios";

const getGraphQLData = async () => {
  const query = `
    query GetUsers {
      users {
        id
        name
        email
      }
    }
  `;
  const { data } = await axios.post(
    "https://your-graphql-endpoint.com/graphql",
    {
      query,
    }
  );
  return data.data; // Note: Axios nests the response in 'data' property
};

function UsersComponent() {
  const { data, error, isLoading } = useQuery("users", getGraphQLData);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>An error occurred: {error.message}</div>;

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

In this example, useQuery manages the fetching, caching, and state of the query. Axios handles the API call, while React Query provides the hooks to integrate the fetched data into your React component with support for loading and error states.

Mutating Data with Axios and React Query

For mutations, you can use the useMutation hook from React Query. This allows you to execute mutation operations triggered by user actions, such as form submissions. Here is how you might set up a mutation to add a user:

import { useMutation } from "react-query";
import axios from "axios";

const addUser = async (userData) => {
  const mutation = `
    mutation AddUser($name: String!, $email: String!) {
      addUser(name: $name, email: $email) {
        id
        name
        email
      }
    }
  `;
  const { data } = await axios.post(
    "https://your-graphql-endpoint.com/graphql",
    {
      query: mutation,
      variables: userData,
    }
  );
  return data.data.addUser;
};

function AddUserForm() {
  const mutation = useMutation(addUser);

  const handleSubmit = (event) => {
    event.preventDefault();
    const formData = new FormData(event.target);
    const userData = {
      name: formData.get("name"),
      email: formData.get("email"),
    };
    mutation.mutate(userData);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" required placeholder="Name" />
      <input name="email" required placeholder="Email" />
      <button type="submit">Add User</button>
      {mutation.isLoading && <p>Adding user...</p>}
      {mutation.isError && <p>Error: {mutation.error.message}</p>}
      {mutation.isSuccess && <p>User added!</p>}
    </form>
  );
}

In this setup, useMutation is used to define a mutation operation. The mutate method from the useMutation hook triggers the actual mutation call with the necessary user data, managed by Axios. React Query then handles the asynchronous state of the mutation, providing feedback on the mutation's progress and outcome.

What to choose ?

  • Choose Axios + React Query if you need a flexible solution that handles more than just GraphQL, require precise control over HTTP requests, or you’re integrating GraphQL in a project that already uses React Query for data fetching.

  • Choose Apollo Client if your project is heavily based on GraphQL, benefits from built-in state management features, and you prefer a more integrated, less boilerplate solution that is optimized for complex GraphQL operations and real-time updates.