When you start working with Relay Modern it is really important to understand the data flow concept first. I will explain this with some cute diagrams from my recent BarcelonaJS talk. I hope you fall in love with Relay Modern after wrapping your head around its main idea.
First, let’s look at a React component tree:
Right at the top, we have a main parent component. It has 2 child components (C1 and C2) and C2 in its turn has C3 and C4 as children. The top level parent is a root component of a React tree and a root of a Relay tree at the same time.
These components have specific names in the Relay Modern world.
We call the main parent component a Query Renderer because it is responsible for sending GraphQL queries to the server, for processing responses to provide data to its children (on all levels) and for actually rendering a React tree.
All of its children in turn are called Fragment Containers because each one contains its own data requirements, usually described as GraphQL fragments.
Let’s look at the diagram again.
Each of these colourful dots represents a data requirement (GraphQL query fragment) that a child expects to be rendered. To combine fragments into one query they need to be referenced from the lowest levels up to the top.
For example, C4’s query fragment is referenced inside the fragment of C2 which is further referenced in the GraphQL query of the Query Renderer. This way, the Query Renderer knows about all of the data requirements of its child components (Fragment Containers) and can then combine these requirements into a GraphQL query and send it in one request to the GraphQL server.
So, once again, Fragment Containers only describe their data and do not send actual requests to the GraphQL server. Simply said, for a component tree to be rendered, the Query Renderer gathers the data requirements of its children into one requirement (query) and sends it to the server.
But what happens after Relay receives the response from the server?
Well, it is then given back to the Query Renderer 🙂
In case of a success, it receives the requested data and distributes it to its children. In case of a failure, it receives an error which can then be shown to the user.
Imagine the request was successful and we received a JSON in the form of a GraphQL query (this is how GraphQL actually works, right? 🙂
There is no magic here, we just need to provide the data normally down the tree through props. By default, each Fragment Container expects a prop called data but the name can be configured in a fragment.
As you can see, the diagram of requirements looks basically the same as the diagram of data distribution, only the directions of the arrows have changed.
Finally, the parent has fulfilled its life purpose and all the children are happy 🙂
Finally, I’d like to share a bit of advanced information with you:
- React/Relay trees are usually much more complex than the example above. Query Renderers can be even nested. However, the nested Query Renderers combine and send their own queries and are ignored by higher level Query Renderers. This mitigates duplication in the queries and data overfetching.
- The Query Renderer does not have direct access to the data in fragments, so you cannot render, for example, the data of C4 inside the Query Renderer directly. C2 also has no access to the data of C4. This data is basically masked until it comes back into C4. Again, it helps prevent overfetching the components and data duplication.
- Relay comes with a lot of optimizations besides the ones described above. One of them (and this is a huge selling point for me) is static query generation at compilation time. Using the relay-compiler package you can generate one static file per fragment/query and it will contain GraphQL artefacts in a form that the GraphQL server understands. There is no query preparation on runtime which means that Query Renderers are ready to send their queries already compiled in advance! As a bonus, each generated file includes a flow type that you can than import in your corresponding fragment container or in any other parts of your app for additional control over the data you receive from the server. Furthermore, the relay-compiler gives you compilation errors in case you incorrectly type your GraphQL code as it is checked against the GraphQL schema provided by the server.
- Go on, head over to Relay docs to see more 🙂
- Or drop me a message in the comments 😉