What we learned from starting from scratch with Relay
We’ve recently adopted Facebook’s Relay Modern for our React Native app.
As you’ll see if you read on, we hit upon a number of massive benefits over the way we were working previously:
- Self-descriptive components
- Goodbye huge chains of props!
- Super speedy to adapt your client code to any server model changes
- Way less code
- Much easier to maintain
The old way…
Like many teams working with React, we followed common wisdom at the time and used Redux with an async library (in our case — Redux Saga) to talk to our server.
Our main priority has been sustainably fast iteration speed — we want to be getting new features out to our users as quickly as possible, without hindering our long-term ability to maintain our project.
Relay Modern, in conjunction with simple server-side iterations using Django (and Graphene) has been SIGNIFICANTLY quicker than using Redux & Node w/ REST. We wanted to write a blog (or maybe 3!) to highlight Relay Modern’s strengths and simplicity.
Giving Relay a try…
For this we’ll assume you’re familiar with GraphQL. If not, you’ll probably find the syntax intuitive enough to be able to follow along. Or, get stuck into some of these blogs.
Relay sits in your mobile or web-app, and provides the layer between your GraphQL server and your React components.
Let’s take an example from our app. We want to compare financial providers and get our community’s thoughts on them.
We’ll build a basic version of this — a screen to display user reviews for a company. The component hierarchy looks like this, with the data required represented next to it as a GraphQL query:
Assuming we know the companyId
, we only need to make one API call (i.e. one Relay query) to fetch all this data. We can bind this query to the top-level ReviewsScreen component. For any components beneath this, we describe the data they need in what’s called a fragment.
The data required for each component will then be available without having to pass down loads of props 🏆
So how does this look in code? Let’s first take a look at our top-level ReviewsScreen component:
class ReviewsScreen extends Component {
// React stuff here
}export default withQueryRenderer({
query: graphql`
query ReviewsScreenQuery($id: ID!) {
viewer {
company(id: $id) {
...CompanyHeader_company
reviews {
...Review_review
}
}
}
}
`
}, ReviewsScreen)/**
* withQueryRenderer is a wrapper we've built for Relay's
* <QueryRenderer /> component to make the syntax less verbose
**/
This looks a little complicated, but actually this is just very concisely describing what data we need in ReviewsScreen
and the components below.
The syntax CompanyHeader_company
says: “Pass down any data on the company
prop that the CompanyHeader
requires.”
Let’s have a look at the component for displaying a review:
class ReviewThumbnail extends Component {
// React stuff here
}export default createFragmentContainer(ReviewThumbnail, {
review: graphql`
fragment ReviewThumbnail_review on ProductReview {
userName
reviewText
upvotes
downvotes
datePosted
}
`
})
Remember…the notation ReviewThumbnail_review
is named by convention: [ComponentName]_[propName]
.
Each of our components is now super descriptive. All the data each component needs is displayed directly alongside it. Better still, when we inevitably change where data is needed, we just change the data in the fragment — no more having to change what variables are being passed between components!
Relay does quite a bit of magic here — it stitches the fragments together inside the top-level query, makes the queries on your behalf and caches any data it knows you have.
The 2 most important tips we can give you!
As powerful as Relay is, it doesn’t offer a great deal of guidance on exactly how to use it. There are a few guiding principles we have found useful.
❌ Passing down props
React/Redux veterans will be well-versed in spending their lives passing props down the component tree. You’ll be pleased in Relay-land, we have now learned to be suspicious of passing down lots of props.
Generally the only props most components will need will be the GraphQL node used by the fragment — e.g. review
for ReviewThumbnail_review
.
You should question whether any other props are needed. {…{ props }}
should sound the alarm that you’re probably passing down props you don’t need to be.
One overlooked benefit here is that it makes it a lot easier to remove code, which is something you should be doing often if you are experimenting with your product. Now that components are self-descriptive, they are far less tightly coupled.
✅ Be strict about using fragments
No matter how trivial the component, if it uses GraphQL data, make sure it has a fragment alongside it.
It can be easy to get drawn into passing down a singular variable to a simple component, which soon leads to 2, and before you know it your code is no longer declarative and it’s all a bit of a mess.
New to Finimize? We’re on a mission to empower millennials to become their own financial advisors.
Find out more by subscribing to our financial email newsletter, downloading our app, or checking out our jobs page.