GraphQL with React Hooks

React Hooks is a new React API, that came in 16.8 version and since then has been getting a lot of buzz. The reason for that is mostly that now we don’t really need to create class components for using state or lifecycle methods. In fact, you can ditch lifecycle methods completely, cause with hooks you can use useEffect for anything, you’ve used previously for lifecycle methods.

So now when hooks are out, let’s see if we can use GraphQL with hooks. But before let’s discuss in a nutshell how we can use GraphQL with React and Apollo.
This post will assume you have basic knowledge of GraphQL, but if you don’t, you can check my free online bootcamp with 9.5h of live coding and teaching lost of aspects of GraphQL.

In the following code snippet, we are setting ours ApolloProvider for queries, mutations, and subscriptions. Also, our GraphQL API endpoint has an access key so we create an authLink and wrap ours httpLink with it. for WebSocketLink we set our headers inside connectionParams.

Our GraphQL API is auto-generated with the hasura.io free and open source engine, so if you are interested in learning more about that you can check the following video:

In the snippet above we set up our ApolloProvider and pass it with our ApolloClient configuration. Now it’s time to query our GraphQL endpoint.

We do that with Query component imported from react-apollo and providing it with render prop, which will get either query result data error or loading states. It looks like this:

import { Query } from ‘react-apollo’
export const Posts = () => (
<Query query={getPosts}>
{({ data, loading, error }) => {
console.log(error);
if (error) return null;
if (loading)
return <div>Loading…</div>;
return data.posts.map(post => (
<div>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
));
}}
</Query>
)

Mutation will look similar but instead of having data,error and loading states, it will provide mutation function as the first argument. whichever data we send as an argument to this function will be passed to our GraphQL mutation

<Mutation mutation={addPost}>
{(addPost, { data }) => (
<div>
<form
onSubmit={e => {
e.preventDefault();
addPost({
variables: {
title: title.value,
content: content.value,
authorId: ‘2808238d-5365–4a70-af52–1de6178bb090’
},
refetchQueries: [{ query: getPosts }]
});
}}
>
</form>
</div>
)}
</Mutation>

Subscriptions will look pretty much the same as queries, so I won’t include a basic example.

It’s time to change everything to work with Hooks!

Let’s get back to our App.js. Nothing will change there, but instead of using

import { ApolloProvider } from ‘react-apollo’

we will use

import { ApolloProvider } from ‘react-apollo-hooks’

Now inside our Posts component we won’t use Query anymore.
we will import useQuery from react-apollo-hooks and use it in the following way:

import {useQuery } from ‘react-apollo-hooks’;
export const Posts = () => {
const {loading, data, error} = useQuery(getPosts);
if (loading) return <div>Loading…</div>
if (error) return <div>Error</div>;
return data.posts.map(post => (
<div>
<h3>{post.subject}</h3>
<p>{post.content}</p>
</div>
));
};

Now for mutation instead of using Render Prop, we can also use useMutation from react-apollo-hooks and use it in the following manner:


const addPostMutation = useMutation(addPost)

return (
<div>
<form
onSubmit={e => {
e.preventDefault();
addPostMutation({
variables: {
subject: title.value,
content: content.value,
userId: ‘a29aa6ae-8cfc-43f9–997e-73baf21835d8’
},
refetchQueries: [{ query: getPosts }]
});
}}
>
</form>
</div>
)

Using mutations and queries as hooks help us a lot with nesting of our Mutations and Queries. Consider this:

In this gist, you see nesting of query inside a mutation. 
Now take a look at implementation with hooks:

Not only it looks cleaner, but we’ve also added a setState hook to change our inputs to be connected to PostMutation state.

Now let’s take a look at subscriptions.
The only thing that we need to change in our Posts component is to change getPosts query itself to be subscription


const getPosts = gql`
subscription getPosts{
posts {
subject
content
}
}
`;
```

and import useSubscription from react-apollo-hooks instead of using useQuery


export const Posts = () => {
const {loading, data, error} = useSubscription(getPosts,
{ suspend: false });
if (loading)return <div>Loading…</div>
if (error) return <div>Error</div>;
return data.posts.map(post => (
<div>
<h3>{post.subject}</h3>
<p>{post.content}</p>
</div>
));
};

react-apollo-hooks has lots of additional stuff inside like experimental Suspense support for example. In a nutshell, it means that instead of getting loading state from useQuery, we now can wrap the component with Suspense and provide it with a fallback for our loader.
Like this:


export const App = (
<ApolloProvider client={client}>
<Suspense fallback={<div>Loading…</div>}>
<Posts/>
</Suspense>
</ApolloProvider>
)

Conclusion

So to summarize. Using GraphQL with React Hooks is really straightforward and hopefully, at some point, we can benefit from using GraphQL with hooks at official Apollo client. Currently, you can use it with react-apollo-hooks

Also if you are interested in learning more about GraphQL, Serverless or Web, Mobile, AR, VR or IoT in general, follow me on Youtube or on Twitter