Dissecting React Apollo Render Props
Getting into Apollo GraphQL can be intimidating for a relatively newer coder like me. When I first approached the subject I went through Stephen Grider’s remarkably thorough $12 Udemy course and felt after that I had a decent grasp on the ecosystem. Stephen shows you what it takes to build a full stack app from GraphQL NodeJS server to React Apollo front-end. He shows us how to compose and call front-end queries/mutations using HOCs (higher order components). It’s amazing for learning the foundational basics. However, when I referenced the official Apollo docs I quickly learned that they weren’t fully aligned with the concepts I had learned.
In fact, there are two opinionated ways to structure your queries and mutation components in React w/ Apollo. For those already familiar with “render props” this probably won’t be an issue and you might feel like passing on this article altogether. But at the time, this difference in strategies caused a lot of confusion for me. I had just learned the ins-and-outs of HOCs and my brain would veritably shut down every time I looked at one of those funky “render props”. My hope is that after reading this you’ll be slightly less confused about what’s happening with these confounded things.
Note: This article assumes some existing knowledge of React, Apollo, Higher Order Components, etc. If you’d like to learn more about setting up your own GraphQL environment I’d suggest starting with https://www.howtographql.com/. After that I’d suggest checking out Scott Tolinski’s Apollo Client Tutorial for up-to-date in depth explanations of concepts covered here.
Render Props vs. Higher Order Components
GraphQL is still new. Developers are still figuring out the ‘right way’ to do everything. The Apollo docs rarely mention the higher order components that many older tutorials still use, yet many examples can be found across forums, blog posts, slack channels, and GitHub issue threads. Let’s look at how each one differs…
The graphql HOC
We need only two things to transform our query data into something our front-end app can use. The graphql HOC from react-apollo and the gql function from apollo-boost or graphql-tag packages. The gql function (yes, it’s a function) uses tagged template literals (similar to Styled Components) to parse our GraphQL string into something usable. We then pass the variable into the graphql HOC and wrap our component.
The graphql HOC passes down a single prop to our wrapped component called data . Which we can access by de-structuring off of props. On data exists a loading indicator, an error object, and eventually the payload itself which in this case is an array of objects called things. We de-structure those off of the data prop. And prevent our component’s main body from rendering if it’s still loading or if there’s an error. Once both of those conditions are false then our data should be available and we can incorporate it into our main return block.
The Query Component (render prop)
This works in more or less the exact same way as the HOC. Instead of using the graphql HOC we use a Query component from the react-apollo package. The Query component takes a prop of query which receives our GraphQL query variable from our gql function declaration. In addition to data we also get a loading and error prop returned back to us so we can de-structure those right out of props. Ok so far so good. Then…
Holy curly braces batman! That’s pretty much what I said when I first saw this. But we’re going to break it down step by step by building our own version of this component. And hopefully demystify this thing a bit.
The Query component’s child is a function
Render props are often used to encapsulate some kind of logic which they pass down to another component. They do this by rendering a function passed to them via props. You can do this by creating a prop called render (or whatever else you might want to call it) or by passing a function in as a child component. The latter is the method Apollo uses.
The first curly brace sets up an area where we can pass the Query component a function to call. We can do this because the Query component itself takes a function as a child and calls that function in it’s render block by looking at props.children. We can simulate a very basic example of this by attempting to re-create the functionality of this component.
Here you can see our FakeQuery component calls props.children in it’s return statement. The function we are passing here doesn’t do anything. It just returns null. So our FakeQuery component isn’t doing a whole lot yet.
Returning from props.children
We can also use the props.children function in the FakeQuery to return values back to our render block in our main component. It’s a function after all. So passing data in as an argument will make it available to our function in MyComponent. Simply passing a string of ‘Hello World’ will make the entire “props” passed to the function a string that says ‘Hello World’. Console log confirms.
Passing in our Query as a Prop
Here we’re doing two things to replicate the Query component. We’re passing the query we created with the gql function as a prop named query and we’re passing a temporary data object into props.children. Now, we can de-structure those properties in our arrow function and console log them to make sure everything is working. Feel free to console.log the query prop passed to FakeQuery as well. I honestly have no idea what any of it means, but you can verify that it has been transformed from the template literal string that we initially passed into it into something presumably much more useful.
Querying the Client
There are probably a few different ways to tackle this next one. But, we need a way to query our GraphQL endpoint from within this Query faker component. For that we can use the client object passed into our ApolloProvider created when setting up an Apollo App so we can return the result to props.children. Apollo comes with an HOC named withApollo which exposes the client object for our FakeQuery component to utilize via it’s props and query off of directly.
I’ve renamed the FakeQuery component to Query since at this point it functions similarly to the way the Apollo Query component works and we’ll need to wrap our component with the HOC and declare it as FakeQuery . I’ve also converted Query into a stateful class component so we can update it’s state once our query resolves.
We can then use the client.query method which takes an object with a property of query to send our query off to the GraphQL endpoint. For this I’ve used an async componentDidMount() that will await the result of the query before spreading the result into state and finally return our props.children with the response passed as an argument. Until then, we’ll return a default state of {loading: true, data: null} so our main component will load without error.
And with that we have created some kind of fairly hacky version of the Query component used by Apollo. I’m sure there’s a lot more going on than this, but in terms of helping you understand how render props work in this context I think this is a decent example.
Wrap Up
As I’ve mentioned, this is by no means intended to be a 1:1 version of the Query component Apollo uses. I haven’t looked at their code. I don’t really know how it’s all working. But I hope that the process of stepping through building our own render prop Query component helped you understand how data is getting passed around in an Apollo app. And maybe relieved some of your curly brace anxiety.
If you feel like you have a better understanding of how things work, but you’re still aggravated by how much boiler plate you have to write feel free to check out my React Apollo snippet library for Atom. And if you have any thoughts on how to improve it submit a PR and let me know!