October 10, 2017

Apollo Tote, Declarative Patterns and a Sneak Peek into Apollo 2.0

Peter Piekarczyk

Peter Piekarczyk

This is a guest post from Peter Piekarczyk, technical co-founder and Apollo / React Native guru at Orchard.ai.

Apollo Tote is a declarative React component. Take what you’ve been doing inside your “smart” containers and apply it with JSX! It’s meant to be a simple helper library for your Apollo queries until declarative components are released in Apollo 2.

I created this because I don’t believe separate components and containers need to be applied everywhere. There are times where I’d prefer to see everything in one, succinct file.

I came up with the idea for Apollo Tote while working on Orchard Ai. We’re utilizing Expo and Apollo to help you stay on top of your relationships & network the same way you do about diet, health and fitness.

At the very minimum, give it a query and a few render props:

<ApolloTote
    query={`
      user {
        imageUrl
      }
    `}
    renderLoading={() => <Avatar.Loading />}
    render={result => <Avatar imageUrl={result.user.imageUrl />}
/>

Note: Apollo Tote is not meant to be used everywhere. We only support queries for now. That being said, there are places where Apollo Tote shines!

Use Cases

Logged In / Logged Out (Authentication / Authorization)

Authentication & Authorization have always been a drag, for whatever reason. You’ll save a user token in localStorage, but you start to realize there’s a few cases you need to handle:

  • A token exists but the user no longer does (this sounds so dark IRL)
  • A token exists but has expired
  • There is no token (this one’s easy!)
<ApolloTote
    query={`
      query {
        user {
          id
        }
      }
    `}
    test={data => !!(data && data.user && data.user.id)}
    handleFail={() => Store.dispatch({ type: 'LOG_OUT' })}
    handlePass={() => Store.dispatch({ type: 'LOG_IN' })}
    renderError={error => this._renderError(error)}
    renderLoading={() => <App.Loading />}
    render={() => <App />}
/>

renderError, renderLoading, render are all Apollo-specific and map directly to { error, loading, data }.

test, handleFail, handlePass are additional helper methods you can use to test for something specific.

In this case I’m testing for user.id, but you can use it for anything where you might use branch in Recompose: anything that needs to pass or fail.

In this case, I’m dispatching LOG_IN / LOG_OUT with Redux, but feel free to use an event emitter or call a class method, etc.

Handling Loading / Error States

I like to load a different component when I’m handling error state. My favorite way of doing that is by exporting a Loading component. This way I don’t have to fk around with any of the styling to get the loading state I’d like. It just works!

Apollo Tote makes that super easy for ya by giving you the renderLoading prop:

<ApolloTote
    query={`
      query {
        user {
          imageUrl
        }
      }
    `}
    renderLoading={() => <Avatar.Loading />}
    render={value => <Avatar imageUrl={value.user.imageUrl} />}
/>

Final Thoughts

Apollo Tote & render props are a great option when it comes to working with a complex application structure. While Apollo Tote is around today, a version of it will appear in Apollo 2. I’ll keep the API as similar as I can so when its ready, all you’ll have to do is replace the import!

This is an awesome opportunity for the community to help make Apollo 2’s declarative components an awesome experience.

Shoutout to my friends Kye Hohenberger and Kyle Shevlin for the feedback. It’s something I always appreciate!

If you want to find out more about Apollo Tote:

  • Check out Apollo Tote on Github.
  • Sign up for the Orchard Ai beta for a sneak peek of it in action. 🙂
  • Follow me on Twitter & Github and learn more about what I’m working on!

Written by

Peter Piekarczyk

Peter Piekarczyk

Read more by Peter Piekarczyk