Firstly, and in very simple terms, Relay is the data framework that lives inside the app, and GraphQL is a query language used within Relay to represent the data schema. GraphQL is also run on a server separately from the app to provide a data source for Relay to interact with (we will be covering the GraphQL server setup in a future tutorial, stay tuned!).
Relay isn’t derived from the Flux architecture and is used only with GraphQL, which immediately means a big difference from the Redux model. The Store/Reducer/Component interaction we covered in the data tutorial does not really exist with Relay. It takes a different approach, and removes a lot of the building work you normally need to do when integrating data.
With Relay, each React component specifies exactly what data it depends on, using GraphQL. Relay handles everything about fetching that data, providing the component with updates when the data changes, and caching the data client-side. Anytime the app wants to change the data itself, it creates a GraphQL Mutation instead of an Action as with Redux.
Redux is a state manager, it’s not even tied to React. If you want to work with any application state in a predictable manner, and that’s what you really care about, redux is what you pick for that application. Redux will not answer the many other concerns that Relay will. Also, redux work with any backend and does not assume anything about the shape of your data. It just contains it.
Relay is a React extension, and it completely depends on GraphQL. If you have a React application, and you’re willing to make its backend a GraphQL server, then Relay is an option. Why you’d pick Relay over Redux in this case? Well:
- Do you need caching?
- Do you need to do any pagination?
- Do you need automatic retries and error handling?
- Do you need to do optimistic mutations (update the UI while the data is in flight)?
If you do, then doing these features with Relay would be much easier than doing them with a Redux-based application.
Relay also has the argument that co-locating your UI with its data requirements makes your application easier to understand and maintain, of course this is mostly GraphQL not Relay, and it’s actually easy to adopt the same concept without using Relay if you have a GraphQL backend.
Learn them both, and build things with them both, and only then you’ll have the better idea of which applications suit one or the other.
- For Redux: The by Dan Abramov are great!
- For Relay (and GraphQL): There is a that I hear is a good start 😉
Both Redux and Relay were inspired by Flux, an architectural pattern for designing your applications. The basic idea of Flux is to always make your data flow in one direction in the application, from your Stores to your (React)Components. Components call Action Creators, they dispatch Actions that your Stores react to.
Relay is in many ways inspired by Flux too. There is a central store, changes to it are made through actions (called Mutations in Relay). However, Relay doesn’t give developers control over the contents of the Store. Rather, Relay leverages GraphQL query language to automatically decompose, store and modify the data received from the server. Components declare their data requirements via GraphQL query fragments and Relay automatically composes the query that fulfills the requirements of all components in the current component tree. Modifications to the Store can be done through a declarative mutation API, but all mutations correspond to server-side mutations. Unlike Redux, you can only store data that has corresponding data on the server in Relay and the server must have a GraphQL API.
Relay provides many features out of the box. Relay handles all the data fetching and makes sure that all (and only) the required data is fetched. Relay has rich support for pagination, especially for use cases isomorphic to infinite scrolling. Relay mutations can perform optimistic updates, report their status and rollback.
Redux encourages separating the presentation and data logic through a concept of smart and dumb components. Usually smart components are created by Redux, they subscribe to a store and can dispatch actions. Dumb components are just normal React components. Smart components describe the data that they require by defining a function that maps store state to their props. Multiple smart components can exists, but usually the component hierarchy should be kept dumb and it should get the data through props.
Redux requires a top level component called Provider that will pass all the props needed by Redux smart components into the React context.
In Relay most components are smart. Relay wraps React components in Relay Containers. Containers declare what data they need to render with a GraphQL fragment. Containers can compose fragments from their child components, but the actual requirements are opaque. This way containers are isolated from each other and it’s possible to reuse or change them without worrying about data not being available. Resolved fragments are passed to the component as simple props.
Relay is used to sync server-driven state to the client so that the client is always in sync with the server. It defines a communication and caching layer when talking to the server which is much better than having to write a ton of REST calls etc.
However, not all state is server driven.
Some state comes from the client. For example – location information.
If you’re in a React Native app, maybe you have a page that should show photos from the phones Photos store? thats local state too.
Relay can’t handle local state. Thats where Redux comes in…