One of the main goals of Apollo Client and the Apollo project in general is to fit seamlessly into the modern React developer’s toolbox. That’s why we’ve invested in simple higher-order components, server-side rendering, and React Native.

Increasingly, React developers are working more and more with small, focused components, and the Recompose library by Andrew Clark takes that to the next level. When Andrew presented it at React Europe last year, he referred to it as a toolbox like Underscore or Lodash, but for React components. Here are some things you can do with Recompose:

Optimize your React components by making them pure-rendered

Set default props

Add limited state variables

And you can do all of this while using the React functional component syntax, which makes your code much more straightforward and reduces your chances of accidentally introducing some state or complexity into your UI rendering.

The React higher order component you use from react-apollo fits this mold. It just does one thing well: It enables you to co-locate your GraphQL query with your React component and get that data in your props , while handling all of the details like fetching and caching the data. It doesn’t do anything else, like manage variable state. That’s where React component composition and Recompose come in.

We can attach GraphQL data, loading management, variable state, or pure rendering in just one function call!

Without further ado, here is our first end-to-end example of how to use Recompose together with React Apollo to have a nice, concise UI with GraphQL!

Manage your variables using ‘withState’

The best feature of functional components is that they are stateless. This means for a certain set of props you will always get the same output, making the component predictable and easy to test. However, sometimes you still want some temporary state, and it’s best to put that outside of the component that handles rendering to keep things clean.

Let’s look how we can use the withState container from Recompose to build a React component that has both a search box and a GraphQL query that uses that search term:

import React from 'react' ; import { withState , pure , compose } from 'recompose' ; import gql from 'graphql-tag' ; import { graphql } from 'react-apollo' ; import { Link } from 'react-router' ; const BookSearchResultsPure = ( { data : { loading , bookSearch } } ) => { if ( loading ) { return < div > Loading < / div > ; } else { return ( < ul > { bookSearch . map ( book => < li key = { book . id } > < Link to = { ` /details/ ${ book . id } ` } > { book . title } by { book . author . name } < / Link > < / li > ) } < / ul > ) ; } } ; const data = graphql ( gql ` query BookSearchQuery($keyword: String!) { bookSearch(keyword: $keyword) { id image title author { id name } } } ` , { options : ( props ) => ( { variables : { keyword : props . keyword } , } ) , } ) ; const BookSearchResults = compose ( data , pure , ) ( BookSearchResultsPure ) ; const keyword = withState ( 'keyword' , 'setKeyword' , '' ) ; const BookSearchPure = ( { keyword , setKeyword } ) => ( < div > < input type = "text" value = { keyword } onChange = { ( e ) => setKeyword ( e . target . value ) } / > < BookSearchResults keyword = { keyword } / > < / div > ) ; const BookSearch = compose ( keyword , pure , ) ( BookSearchPure ) ; export default BookSearch ;

One nice side effect is that since we are keeping all of the state and data loading outside of the component, we can drop in the pure mix-in everywhere to make sure our components don’t rerender when they don’t need to.

In the above code snippet, all of our concerns are very nicely separated through the React component paradigm. We have two components for rendering HTML, one for keeping track of the search box state, and one for data loading. We can test and inspect each one separately.

Displaying loading state with ‘branch’

One thing that’s not so nice about the BookSearchResultsPure component above is that it has an if statement with multiple returns. This means you have to interpret that logic in your mind to see what the result might look like. We could also use an HoC to flatten this out:

import React from 'react' ; import { pure , branch , renderComponent , compose } from 'recompose' ; import gql from 'graphql-tag' ; import { graphql } from 'react-apollo' ; import { Link } from 'react-router' ; const Loading = ( ) => ( < div > Loading < / div > ) ; const displayLoadingState = branch ( ( props ) => props . data . loading , renderComponent ( Loading ) , ) ; const BookSearchResultsPure = ( { data : { bookSearch } } ) => ( < ul > { bookSearch . map ( book => < li key = { book . id } > < Link to = { ` /details/ ${ book . id } ` } > { book . title } by { book . author . name } < / Link > < / li > ) } < / ul > ) ; const data = graphql ( gql ` query BookSearchQuery($keyword: String!) { ... } ` , { options : ( { keyword } ) => ( { variables : { keyword } } ) , } ) ; const BookSearchResults = compose ( data , displayLoadingState , pure , ) ( BookSearchResultsPure ) ;

Now, we can very easily share a common loading component between all of our UI that uses data from React-Apollo, and the logic is contained in a separate chunk that isn’t obscuring the structure of our pure component!

Take-away

The react-apollo API was designed to be the best way to pull GraphQL data into the props of a React component. Combined with a library like Recompose, it gives you an incredibly powerful and flexible way to declaratively connect server-side data to your react components while keeping them pure.

Abhi Aiyer has already written a great follow-up about how to use Recompose to work nicely with mutations:How I write Mutations in Apollo w/ RecomposeSince Sashko Stubailo launched his post about Apollo + Recompose, which is a great blog post by the way, I wanted to show everyone how I…medium.com

Thanks Abhi! And if anyone else has great ideas about how to use Apollo and Recompose together, please let me know in the responses!

Want to work full-time on GraphQL technology, collaborate with the open source community, and write articles like these? We’re actively hiring for a variety of positions! Check them out.