I’ll be using the AWS Amplify GraphQL client with an AWS AppSync API in this example, but if you’d like to follow along using the Apollo client, you can use the client with a similar API by using the following configuration:

Queries

Update: In the future, React Suspense & React-cache will have a first-class method of handling asynchronous data fetching & will provide a possibly better API for queries. I’ve set up a working example here if you’re interested in new & unstable things 😀.

The first thing we’ll look at how to do is perform a GraphQL query. There are two ways to think about doing this:

Query immediately when the component renders Have a button or event that triggers the query

Let’s look at how to do both.

Hook to query when the component renders

In this example we’ve created a hook to query from the GraphQL API immediately when the hook is called.

We use the useState hook to create some initial state, setting the todos array to an empty array.

When the hook is used, useEffect will be triggered, querying the API & updating the todos array. Here, we’re using useEffect similarly to how you might have used componentDidMount in a class component.

Finally, the hook returns the most up to date version of the todos array.

Now, how would we use this hook? Well, it’s actually pretty easy:

When we call useQuery , it returns an array with the most up to date version of our todo list. In the view we then map over the todos array.

Manually calling the query

What if we wanted to wait for an event before calling the query? Let’s take a look at how to call the query when a user clicks on a button.

In this hook, we have a function called queryTodos that we will be using to call the API. The main difference here is that we are no longer using the useEffect hook to handle any side effects. When the hook loads, we don’t really do anything other than set some initial state.

In the return we now are returning an array of values vs a single value. The first value is the array of todos, the second value is the function call to trigger the API operation.

Now, when we want to use the hook we can import the two values from the hook:

Mutations

Now that we know how to query for data, let’s look at how to create mutations.

Well, there’s actually no hook needed for mutations. They can be created directly from the component:

Subscriptions

One very cool use case (& one that fits perfectly with the paradigm of hooks) is handling GraphQL subscriptions.

Because subscriptions have been typically created & torn down using lifecycle methods in a class, the new useEffect hook from React is the perfect place for subscriptions to be implemented.

For this example, we’ll first query the initial array of todos & store them in the state when they are returned in a useEffect hook when the component loads.

We’ll create another useEffect hook to create a GraphQL subscription. The subscription will listen for new todos being created. When a new todo is created, the subscription will fire & we’ll update the todos array to add the new todo in the subscription data.

The way that we’re managing state here is different than in the past when we used useState . Here, we’re using a reducer by leveraging the useReducer hook because we need to share state across multiple effects but only want the subscription to fire when the component loads. In order to achieve this, we’ll manage all of our state in this single reducer that will be used in both useEffect hooks.

In the above subscription hook, we first fetch the initial array of todos. Once they come back from the API, we update the todos array in the state.

We also set up a subscription to listen for new todos, when they are created we update the todos array in the state.

In the main application, we import the todos & map over them in our UI.

Getting subscriptions to work properly with useReducer took some time for me to figure out. Thanks to hurabielle marc for helping me figure out the solution!

Conclusion

I have not touched on caching or optimistic UI / working with the Apollo store, though I would be really interested to see some examples of hooks that managed caching / optimistic UI.