My FeedDiscussionsHashnode Enterprise
New
Sign in
Log inSign up
Learn more about Hashnode Headless CMSHashnode Headless CMS
Collaborate seamlessly with Hashnode Headless CMS for Enterprise.
Upgrade ✨Learn more
Implement Apollo Client in React

Photo by Lautaro Andreani on Unsplash

Implement Apollo Client in React

Saurav Kumar's photo
Saurav Kumar
·Feb 10, 2022·

5 min read

In this article, we are going to see how we can use apollo-client to query or mutate data from our GraphQL API, before that let's see what is GraphQL so, GraphQL is a query language for API's which provide a type system that describes the data of our API and gives the client the power to ask the exact data that they need, wherein a REST API sends the entire data and the client doesn't have any control over the data that they are receiving. So, GraphQL solves this problem of under and over-fetching of the data by sending the exact data that the client has requested.

Now let's discuss apollo and apollo-client, apollo is a platform that provides us the code to work with GraphQL(full-stack) and apollo-client is an implementation for the client-side to work with GraphQL. Apollo-client is not just to fetch data from a GraphQL server but also a state management library for javascript that fetches, cache, and modify application data with GraphQL. In this article, we will see how we can use apollo-client to fetch and update data from a GraphQL API, so let's get started.

Setup

First, we need to install the graphql and apollo client packages it has everything that we need to set up Apollo Client on our client-side.

 npm install @apollo/client graphql

Initialize ApolloClient

Now that we have installed the dependencies let's initialize an ApolloClient instance which we will later provide to ApolloProvider.

import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  uri: 'API_URL,
  cache: new InMemoryCache()
});

ApolloClient instance takes an object with uri and cache as its fields, the uri field will take the URL of our API and cache will take InMemoryCache which Apollo Client uses to cache query results after fetching them.

That's all we need to do to initialize our ApolloClient instance but if our API has authorization and we have to send a token to authorize the users then the ApolloClient instance is initialized differently, let's see how it's done.

import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';

const httpLink = createHttpLink({
  uri: API_URL,
});

const authLink = setContext((_, { headers }) => {
  const token = getTokenFromLocalStroage();
  return {
    headers: {
      ...headers,
      authorization: token,
    }
  }
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});

The setContext will provide the header with our token which is stored in the variable authLink and then it is concat with httpLink and used as a field in the ApolloClient instance.

Connect the client to React App

We can connect the apollo client with the ApolloProvider component which is provided by apollo-client.

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

ReactDOM.render(
  <React.StrictMode>
    <ApolloProvider client={client}>
      <App/>
    </ApolloProvider>
  </React.StrictMode>,
  document.getElementById("root")
);

In the index.jsx file wrap your App component with ApolloProvider with the client as its props, the client here is the same ApolloClient instance that we have created earlier. Now we are finally ready to make requests from our GraphQL server.

Fetch data with useQuery

useQuery is a react hook provided by apollo-client to query or fetch data from a GraphQL API. To query data we need to call useQuery within a React component and give the hook a GraphQL query string with the exact data that we want and when the component is rendered useQuery will return an object that contains the requested data, loading, and error that you can use to update the UI of your component.

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

// GraphQL query string
const GET_USERS = gql`
  query getUsers {
    users {
       id
       name
       email
     }
  }
`;

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

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

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

If your query needs a variable to fetch the data then you can give in the useQuery hook as an object, as shown below.

const GET_USER = gql`
  query user($userId: ID!) {
    user(userId: $userId) {
      id
      name
      email
    }
  }
`;

function User({ userId }) {
  const { loading, error, data } = useQuery(GET_USER, {
    variables: { userId },
  });

  if (loading) return null;
  if (error) return `Error! ${error}`;

  return (
    <div>
      <p>{data.user.name}</p>
      <p>{data.user.email}</p>
   </div>
  );
}

Apollo Client by default cached the fetched data this makes the upcoming execution of the same query extremely fast, but if you don't want the cached data and want to fetch again and again whenever the component is rendered, which you can do that by changing the fetch policy to network-only by this it doesn't check the cache for the data and instead makes a fresh network request.

const { loading, error, data } = useQuery(GET_USER, {
  fetchPolicy: "network-only" 
});

There are also some other fetch policies like:-

  • cache-first This is the default fetch policy which checks the cached data first and if the requested data is available then it won't make a new request and sends back the cached data.

  • cache-only As the name suggests it never queries from the server it will look only for the cached data and if it doesn't find the exact data it will throw an error.

  • cache-and-network This fetch-policy keeps the cache up-to-date with what is on the server.

  • no-cache Similar to network-only but the query's result is not stored in the cache.

Modify data with useMutation

We have seen how we can query data from a GraphQL server now let's see how can we mutate or modify our backend data using useMutation.

To mutate first, we need to call useMutation hook inside a react component and give it a GraphQL mutation string, and the variables that it's needed, the hook will provide a function, and when the function is called it will execute the mutation by sending it to our GraphQL server.

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

const ADD_TODO = gql`
  mutation AddTodo($text: String!) {
    addTodo(text: $text) {
      id
      text
    }
  }
`;

function AddTodo() {
  const [text, setText] = useState("");
  const [addTodo, { data, loading, error }] = useMutation(ADD_TODO, {
     variables: { text } 
});

function addTodoHandler(){
    text && addTodo();
}

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

  return (
    <div>
       <input
         type="text"
         onChange={(e)=> setText(e.target.value)}
       />
       <button onClick={addTodoHandler}>Add Todo</button>
    </div>
  );
}

The mutation will be executed only when the button is clicked and not like in useQuery when the component is rendered.

Hope this article had helped you in some way understanding implementing apollo-client in React.