React Apollo and React Hooks - A match made in heaven
We have just finished the second hackathon of the year. This time building a space themed 'EdTech' app for school children. The usual constraints applied - we needed a finished and polished product by the end of the week.
Needing to produce a product fast we leant on our favourite stack: React for the frontend, AWS Amplify for the "backend". As I have spoken about before, Amplify provides the best developer experience when getting complex systems set up. The CLI allows you to easily generate all your AWS resources needed to build full serverless applications.
In this article, I am talking about using React hooks with React Apollo, allowing you to write incredibly terse, readable code.
React Hooks
George has written a couple of great articles discussing the fantastic benefits of React hooks, so I will leave that to him.
React Apollo
Apollo is a GraphQL client helping you to quickly build client applications backed by a GraphQL API. We will be using AppSync from AWS as our GraphQL API and interacting with it with React Apollo but the Hooks implementation will work with any GraphQL API. AWS provides its own client but I prefer to use Apollo.
React Apollo is not perfect though. The Query
and Mutation
components use render props to allow access to the data returned from your API. When you only have a single Query or Mutation this is not a problem. But when you have multiple next components it can quickly get messy and difficult to read. You could use something like react-adopt
to compose render props into something more manageable but with the recent(ish) addition of React hooks there is a better way.
We are going to run through the refactor of a simple project, moving all our Apollo component code to React hooks. We will be leaning on the react-apollo-hooks
package to provide this awesomeness. React Apollo have not released their own implementation of this yet but I imagine it will be coming soon.
The example project is contrived but is all that is needed to get the point across. I am choosing to only have a single Query and Mutation components to make it as easy as possible to understand. If you want to know more about how to set up a project using AWS Amplify and Apollo then check out my previous article. Its focus is React Native but the ideas and implementation are pretty much identical.
Before we can start refactoring we need to install react-apollo-hooks package
Now we need to modify our App.js to make use of the package. We do this by wrapping the application in the ApolloHooksProvider component.
Mutations
Let's start off by looking at refactoring our mutation component.
This is the code we are starting off with:
We start by adding the useMutation hook. We pass in the mutation and assign it to a const for use later. We are then able to use the mutation in a onClick function. With the these updates the new component will look like this:
In this simple example there is not a huge amount of saving in SLOC but it is much easier to read as there is not the tangled mess of brackets that comes with render props.
Querys
Queries work the same way. The data is made available through properties of the render prop. This gets messy once you start nesting, so let's refactor to a hook.
We remove the Query component and its render props and replace it with useQuery
destructuring the required information from the returned data. It will look something like this:
And there we have it. Although the benefits are not obvious from the simple example, once your app grows the use of hooks greatly simplifies your components and this is a win for me!
Conclusion
As I mentioned at the beginning, the examples are very simple and don't show the true power of using hooks with Apollo, but that is not what the examples were for. They needed to be clear. I hope the article makes it clear that the improvements in readability are fantastic.
All the code for this article can be found here.