React Data Fetching with Relay

Share this article

React is ushering a new era in front end. Published by Facebook, it has rapidly become a popular library used in production by many technology companies. In this article, we’re going to discuss a new complementary React framework called Relay.

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 like setQueryParams()
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:
  1. Create a GraphQL Schema
  2. Create a GraphQL Server
It should be noted that it may take a considerable amount of work to convert an existing project to a GraphQL Schema and set up or modify an existing server to be GraphQL-friendly. When starting a project from scratch, it might make more sense to use Relay immediately. Facebook provides a Relay Starter Kit that looks like a great solution for getting up and running with Relay and GraphQL on a new project.

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 use react-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.

Kev ZettlerKev Zettler
View Author

Freelance technologist and founder of RedTrenchMediaCorp, a Y Combinator alumni. Serial entrepreneur. Indie game developer. Punk rocker. Website at: kevzettler.com

AurelioDdatafacebookframeworkFrameworksjavascript frameworkjavascript frameworksReactReact-ToolsReact.jsRelay
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week