Key Takeaways
- Relay is a React data fetching framework published by Facebook, aiming to provide a clear solution to data-fetching problems. It leverages a declarative code style for data dependencies, collocates data dependency definitions with component definitions, and enables seamless data modification.
- Relay is built on the concepts of Flux, but introduces a concept of ‘Higher Order Components’ (HOCs). HOCs wrap child UI components, manage the Flux flow, and act as a dispatcher and a store by persisting data.
- Relay is powered by GraphQL, a new query language from Facebook that operates on graph data structures. This requires setting up a GraphQL Schema and a GraphQL Server, which can be a significant amount of work for existing projects. For new projects, Facebook provides a Relay Starter Kit.
- Relay might not be suitable for existing projects due to the extra overhead required to set up GraphQL. An alternative is react-transmit, a Relay-inspired library based on Promises instead of GraphQL. It’s also noted that Relay is not currently suitable for isomorphic applications, but its future roadmap includes better isomorphic support and adapters for other data storage types.
The Problem with Data Fetching in React
As React has grown in popularity, the scale and complexity of the projects built with React has grown along with it. React is primarily a view layer library. This has caused some teams to hit unknown territory or limitations while building projects that require a different infrastructure. Facebook has been proactive in offering support and guidance during these growing pains.Flux
One of the early growing pains for developers using React was event handling. Facebook responded to this issue by publishing Flux, which is an abstract pattern that encouraged unidirectional data flow for handling events in React. I’ll assume some familiarity with Flux, so I won’t discuss the details of it in this article. In case you aren’t familiar with this topic, you can give a reading to this article by Sandeep Panda or take a look at this page about Flux. Flux has taken the React ecosystem to the next level. As developers started to get more familiar with Flux, some issues emerged. Flux has been great for managing data as application state, but populating the initial state into an application has been a source of friction. There are several challenges surrounding Flux’s data initialization. Do stores call the server and populate themselves? Do we use rehydrate methods from the dispatcher? Do we call a bunch of actions on the server to populate the stores? How do we do this asynchronously and load all our data on the server in an isomorphic app before returning a response?What Is Relay?
Relay is a new React Data fetching framework published by Facebook. Relay aims to provide a clear solution to all of these data-fetching problems. Relay has a few main selling points:Declarative: This is also a main feature of React. Relay leverage a declarative code style definition for data dependencies, which is very similar to how view components are defined. This is a refreshing change from traditional imperative data-fetching APIs.
Collocation: Data dependency definitions live alongside component definitions, which makes it much easier to reason about what data a UI component requires to render. This makes troubleshooting a project’s code a lot easier. Looking at a file that contains a React component definition, it’s immediately obvious what data it needs to function.
Mutations: Mutations enable an experience of seamless modification to data which a React view is subscribed to and also populates those modifications to the data persistence layer.
Relay vs Flux
Flux is an abstract idea whereas Relay is an implementation inspired by that idea. Relay is built on the concepts of Flux and has the same concepts of dispatcher, actions, and stores, but they are represented a bit differently. Relay has a new concept called ‘Higher Order Components’ and we’ll expand on this topic in the remainder of the article. At this stage, it’s still unclear if Relay will replace or coincide with existing Flux implementations. For example, Redux, a popular Flux implementation, also leverage ‘Higher Order Components’. Trying to use both Redux and Relay will cause a conflict over which framework is bound to a UI component. There is currently an ongoing discussion regarding Redux’s relationship with Relay.Higher Order Components
Higher Order components or HOCs are defined in the same way as regular React components. HOCs wrap child UI components. The HOC will execute its queries and then render the child UI component, passing the query data in as props . The Flux flow is now managed by the HOC and the latter will act as a dispatcher. It has methods likesetQueryParams()
that can be considered as a Flux action. Calling setQueryParams()
triggers the Flux flow. The queries defined in the HOC are updated, new data is fetched and the data is persisted in the HOC. The HOC is acting as a Flux store by persisting this data.
Below is a simplified example of a ProfilePicture
component and a complimentary HOC. Imagine that we have ProfilePicture
defined to render user avatars throughout our project. We need to fetch the data to display the user avatar. We then create a Relay HOC to query the user profile pictures from a database. The HOC passes this query data to the child ProfilePicture component:
class ProfilePicture extends React.Component {
// A standard Profile Picture component
}
// This is our Higher Order Component. It fetches the data to pass
// as props to Profile Picture
module.exports = Relay.createContainer(ProfilePicture, {
fragments: {
user: () => Relay.QL`
fragment on User {
profilePicture(size: $size) {
uri,
},
}
`,
},
});
Our ProfilePicture
component will then get some new local functions passed in as props. This essentially is how Relay triggers the Flux flow. The component calls these Relay prop functions, which is equivalent to a Flux action call. This causes Relay to fetch the latest data requested. Once done it populates its internal store and passes that down to the HOC’s child view component as props.
GraphQL
The above example may look a bit strange, particularly this part:Relay.QL`
fragment on User {
profilePicture(size: $size) {
uri,
},
}
`,
Much of the magic behind Relay is powered by GraphQL. GraphQL is a new query language from Facebook that specializes in operating on graph data structures. Discussing GraphQL in depth is outside the scope of this article, however you can deepen this topic by reading the Relay documentation which covers it. An existing project will not be set up to work with GraphQL right out of the box. The first recommended steps to getting started with Relay are:
- Create a GraphQL Schema
- Create a GraphQL Server
Relay Without GraphQL
With all of the extra overhead required to set up GraphQL, Facebook’s Relay might not be the right tool for existing projects. Luckily, there is another Relay-inspired library out there that may be a better fit for these projects called react-transmit. react-transmit is an open source project that aims to be a “Relay-inspired library based on Promises instead of GraphQL.” If we update the profile example from above to usereact-trasmit
then we have the following code:
// Import Transmit
import Transmit from "react-transmit";
class ProfilePicture extends React.Component {
// A standard Profile Picture component
}
// This is our Higher Order Component. It fetches the data to pass
// as props to Profile Picture
Transmit.createContainer(ProfilePicture, {
fragments: {
user: (userId) => {
return new Promise(function(resolve, reject) {
// Do some Ajax here and resolve the promise
});
}
},
});
The react-transmit example looks very similar to the Relay example. However, in this instance the user
fragment is now a function that returns a Promise instead of a GraphQL query.
Current State of Relay
Facebook has released an open source “technical preview” of Relay. They have some great examples in the repository that show how to work with Relay and a very detailed documentation section. It doesn’t seem that Relay is suitable for isomorphic applications at this time. There is no way to tell Relay to wait until all of the data dependencies have been loaded before rendering its child view, something that is needed on the server. In case you’re interested, there is an ongoing discussion regarding how Relay will work on the server. At the moment, this is a pattern that react-transmit is more suited to at the current time. As for Relay’s future, its roadmap aims to provide a few key features soon:- Adapters for other data storage types so there is no hard dependency on GraphQL.
- Better isomorphic support, as discussed earlier.
Conclusions
In this article, we’ve discussed a new React complementary framework called Relay. Relay is built on some of the same concepts of Flux and powered by GraphQL. As I mentioned, Relay might not be a good choice for already existing projects. However, this framework is quite new and I expect it to become better and better at every release. Now, it’s your turn. Did you know Relay? Have you ever adopted it in one of your projects?Frequently Asked Questions about React Data Fetching with Relay
What are the key differences between Relay and Apollo Client?
Relay and Apollo Client are both popular GraphQL clients, but they have some key differences. Relay is more opinionated and requires a specific GraphQL schema, which can make it more difficult to set up. However, it offers performance benefits and automatic data consistency. Apollo Client, on the other hand, is more flexible and easier to set up, but it requires more manual work to ensure data consistency and optimal performance.
How does Relay handle data fetching?
Relay uses a declarative approach to data fetching. This means that you specify what data you need, and Relay ensures that this data is fetched and available for your component. This approach abstracts away the complexities of data fetching and allows you to focus on building your components.
What are the benefits of using Relay for data fetching in React?
Relay offers several benefits for data fetching in React. It provides a structured way to fetch data, ensuring that your components have the data they need when they render. It also handles caching and data consistency automatically, which can improve performance and user experience. Additionally, Relay’s declarative approach to data fetching can make your code easier to understand and maintain.
How does Relay compare to other GraphQL clients like URQL?
Relay and URQL are both GraphQL clients, but they have different focuses. Relay is more performance-focused, with features like automatic data consistency and optimized data fetching. URQL, on the other hand, is more simplicity-focused, with a straightforward setup process and a flexible API. The best choice between the two depends on your specific needs and priorities.
What are the challenges of using Relay?
While Relay offers many benefits, it also has some challenges. It requires a specific GraphQL schema and a more complex setup process, which can be daunting for beginners. It also has a steeper learning curve compared to other GraphQL clients. However, once you get past these initial challenges, Relay can be a powerful tool for data fetching in React.
How does Relay handle caching?
Relay handles caching automatically. It keeps a store of the data it has fetched, and when a component requests data, Relay first checks if this data is already in the store. If it is, Relay uses the cached data instead of making a new network request. This can significantly improve performance, especially for larger applications.
Can I use Relay with other libraries or frameworks?
Yes, while Relay is designed to work well with React, it can also be used with other libraries or frameworks. However, it may require additional setup or configuration, and not all of Relay’s features may be available.
How does Relay handle errors?
Relay provides error handling mechanisms that allow you to catch and handle errors in your data fetching. This includes network errors, GraphQL errors, and more. You can specify how to handle these errors in your Relay environment.
What is the Relay Compiler and what does it do?
The Relay Compiler is a tool that processes your GraphQL queries and generates optimized JavaScript code. This code ensures that your data fetching is as efficient as possible, and it also checks your queries against your GraphQL schema to catch any errors or inconsistencies.
How does Relay handle pagination?
Relay provides built-in support for pagination. You can specify how many items to fetch at a time, and Relay will automatically fetch more items as needed. This can improve performance for lists of data and provide a smoother user experience.
Freelance technologist and founder of RedTrenchMediaCorp, a Y Combinator alumni. Serial entrepreneur. Indie game developer. Punk rocker. Website at: kevzettler.com