loading...

Using GraphQL with Hooks

vladimirnovick profile image Vladimir Novick ・4 min read

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 our ApolloProvider for queries, mutations and subscriptions. Also our GraphQL API endpoint has an access key so we create an authLink and wrap our httpLink with it. for WebSocketLink we set our headers inside connectionParams.

Our GraphQL API is auto generated with 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 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 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 RenderProp 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, we've also added 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 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 library.

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

Posted on by:

vladimirnovick profile

Vladimir Novick

@vladimirnovick

CTO and Co-Founder at Event Loop, Google Developer Expert, consultant, worldwide speaker, published author, workshops teacher, software architect and developer in Web/Mobile/AR/VR/IoT/AI fields

Discussion

markdown guide