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
Top comments (1)
Thank you!