Handle Multiple Queries & Mutations in React Form using Apollo Client
Tags: webdev, react, graphql, apollo
Published: 2023-06-15 16:36:16

In this tutorial, we'll explore how to handle multiple queries and mutations in a controlled form using Apollo Client in a React application. We'll leverage Apollo Client to fetch data from a GraphQL API and update the form state based on user input. We'll also perform mutations to update the data in the database.

Prerequisites:
- Basic knowledge of React and GraphQL
- Familiarity with Apollo Client and controlled forms in React

Let's dive into the step-by-step process:

Step 1: Set up Apollo Client
Start by setting up Apollo Client in your React application. Install the required packages by running the following command in your project directory:
```shell
npm install @apollo/client graphql
```

Next, create an instance of Apollo Client and configure it with the necessary details. In your `index.js` or `App.js` file, import the required dependencies:
```javascript
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
```

Create the Apollo Client instance:
```javascript
const client = new ApolloClient({
  uri: 'YOUR_GRAPHQL_ENDPOINT_URL',
  cache: new InMemoryCache(),
});
```
Replace `'YOUR_GRAPHQL_ENDPOINT_URL'` with the actual GraphQL API endpoint URL.

Step 2: Define GraphQL Queries
Identify the data you need for your form and write the GraphQL queries to fetch that data. For example, let's assume we have a form that requires fetching a list of countries and a user's profile.

Define the GraphQL queries using the `gql` tag from the `graphql` package. Here's an example of querying countries:
```javascript
import { gql } from '@apollo/client';

const GET_COUNTRIES = gql`
  query GetCountries {
    countries {
      id
      name
    }
  }
`;
```

Similarly, define a query to fetch a user's profile:
```javascript
const GET_USER_PROFILE = gql`
  query GetUserProfile($userId: ID!) {
    user(id: $userId) {
      id
      name
      email
    }
  }
`;
```

Step 3: Create the Form Component
Build a React form component that includes the necessary input fields. In this example, we'll use a controlled form approach, where the form fields are controlled by React state.

Import the necessary dependencies and hooks:
```javascript
import React, { useState } from 'react';
import { useQuery, useMutation } from '@apollo/client';
```

Create the form component:
```javascript
const MyForm = () => {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    countryId: '',
  });

  const { loading: countriesLoading, error: countriesError, data: countriesData } = useQuery(GET_COUNTRIES);
  const { loading: userProfileLoading, error: userProfileError, data: userProfileData } = useQuery(GET_USER_PROFILE, {
    variables: { userId: 'USER_ID' }, // Replace with the actual user ID
  });

  const [updateUserProfile] = useMutation(UPDATE_USER_PROFILE);

  const handleInputChange = (event) => {
    const { name, value } = event.target;
    setFormData((prevFormData) => ({
      ...prevFormData,
      [name]: value,
    }));
  };

  const handleSubmit = (event) => {
    event.preventDefault();

    const { name, email, countryId } = formData;

    // Execute the mutation
    updateUserProfile({ variables: { userId: 'USER

_ID', name, email, countryId } })
      .then((response) => {
        // Handle success
      })
      .catch((error) => {
        // Handle error
      });
  };

  if (countriesLoading || userProfileLoading) {
    return <div>Loading...</div>;
  }

  if (countriesError || userProfileError) {
    return <div>Error fetching data.</div>;
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input type="text" name="name" value={formData.name} onChange={handleInputChange} />
      </label>
      <label>
        Email:
        <input type="email" name="email" value={formData.email} onChange={handleInputChange} />
      </label>
      <label>
        Country:
        <select name="countryId" value={formData.countryId} onChange={handleInputChange}>
          <option value="">Select a country</option>
          {countriesData.countries.map((country) => (
            <option key={country.id} value={country.id}>
              {country.name}
            </option>
          ))}
        </select>
      </label>
      <button type="submit">Submit</button>
    </form>
  );
};
```
Replace `'USER_ID'` with the actual user ID.

Step 4: Perform Mutations on Form Submission
Define the GraphQL mutations required to update or create data in the database. For example, let's assume we have a mutation to update a user's profile.

Define the GraphQL mutation using the `gql` tag:
```javascript
const UPDATE_USER_PROFILE = gql`
  mutation UpdateUserProfile($userId: ID!, $name: String!, $email: String!, $countryId: ID!) {
    updateUser(id: $userId, name: $name, email: $email, countryId: $countryId) {
      id
      name
      email
      countryId
    }
  }
`;
```

In the form component, import the necessary dependencies:
```javascript
import { useMutation } from '@apollo/client';
```

Handle form submission and execute the mutation:
```javascript
const MyForm = () => {
  // ...

  const handleSubmit = (event) => {
    event.preventDefault();

    const { name, email, countryId } = formData;

    // Execute the mutation
    updateUserProfile({ variables: { userId: 'USER_ID', name, email, countryId } })
      .then((response) => {
        // Handle success
      })
      .catch((error) => {
        // Handle error
      });
  };

  // ...
};
```
Replace `'USER_ID'` with the actual user ID.

Step 5: Conclusion
In this tutorial, we learned how to handle multiple queries and mutations in a controlled form using Apollo Client in a React application. We set up Apollo Client, defined GraphQL queries to fetch data, created a controlled form component to handle user input, performed mutations on form submission, and updated the form state accordingly. By leveraging Apollo Client and controlled forms in React, we can easily manage complex form interactions and data flow in our applications.

Remember to replace 'YOUR_GRAPHQL_ENDPOINT_URL' and 'USER_ID' with your actual GraphQL API endpoint URL and user ID, respectively.