GraphQLDataWrapper Component

Mitch Masia
hexient-labs
Published in
3 min readAug 1, 2018

Declaratively manage GraphQL data from Apollo Client.

If you’re a fan of GraphQL, you’ve probably heard of Apollo. The team behind Meteor is building awesome full-stack tooling for the GraphQL community.

Anyway, in their recent React Apollo 2.1 release they made a paradigm shift to include declarative data-fetching components that can be used inside a render function, as opposed to just higher-order components that wrap our base components with additional data props.

Image result for react apollo

What does this actually mean?

Well, before the 2.1 release, we had to use Apollo like so:

// ExampleComponent.jsimport React, { Component } from 'react'
import { graphql } from 'react-graphql'
import gql from 'graphql-tag'
const QUERY = gql`
query CurrentUser {
currentUser {
id
firstName
lastName
friends {
id
firstName
}
}
}
}
const ExampleComponent = ({
data: {
currentUser,
error,
loading
}
) => (
<div>
{/* Do something with the data */}
</div>
)
const withQuery = graphql(QUERY)export default withQuery(ExampleComponent)

HOCs are a great tool; however, this is an opaque implementation that doesn’t take full advantage of React’s component-based architecture.

The newer client library introduces a declarative Query component which fully utilizes React’s component system and the hot render-prop pattern.

// DeclarativeExampleComponent.jsimport React, { Component } from 'react'
import { Query } from 'react-graphql'
import gql from 'graphql-tag'
const QUERY = gql`
query CurrentUser {
currentUser {
id
firstName
lastName
friends {
id
firstName
}
}
}
}
const DeclarativeExampleComponent = (props) => (
<div>
<Query query={QUERY}>
{({ data, error, loading }) => {
// Do something with the data
}}
</Query>
</div>
)
export default ExampleComponent

Amazing boost in clarity, right? This snippet looks a lot more familiar and approachable to React and GraphQL newbies and reduces cognitive load on the developer by sticking solely to React components. Using the render-prop pattern, the Query component takes a function as it’s children and that function returns some JSX.

Here lies the issue. A naive approach to using the Query component would lead to a lot of code duplication.

<Query query={QUERY}>
{({ data, error, loading }) => {
if (loading) return <h1>Loading...</h1>
if (error) return <h1>There was an error!</h1>

return <UserProfile user={data.currentUser} />
}}
</Query>

Every time we use the Query component to run a GraphQL query, we’d have repeated conditional, imperative logic for checking loading and error conditions.

GraphQLDataWrapper

At Hex Labs, we hated this problem so we developed a custom component called our GraphQLDataWrapper. It’s a really simple, declarative interface that encapsulates the logic above. Here’s a snippet:

This component abstracts error, loading, and success state from any given GraphQL Query, conditionally rendering default Error and Loading components that can be overridden. We can use the component like so:

<Query query={QUERY}>
{rp => (
<GraphQLDataWrapper
{...rp}
renderData={({ data, ...rest }) => {
// Do something with the data
)}
</GraphQLDataWrapper>
)}
</Query>

Now, instead of individually dealing with errors, and loading states, it’s all taken care of! Woo! And in case you’re curious, the rest key passed to the renderData prop will contain additional render-props from the Query component such as refetch, fetchMore, and variables. You can find the whole list here.

Anyway, I know that’s a lot to take in, but I hope it hopes someone out there DRY up their code :)

Heads up, I’m building a really neat abstraction layer on top of any database that automatically creates REST and GraphQL APIs for you. If you want early access, fill out our survey here!

--

--

Mitch Masia
hexient-labs

Mitch is a developer, teacher, and entrepreneur building cool things at Guaranteed Rate.