Skip to content

Commit 1997047

Browse files
captbaritonefacebook-github-bot
authored andcommitted
Add blog post explaining how Relay provides unique value in data loading
Reviewed By: voideanvalue, alunyov Differential Revision: D50606876 fbshipit-source-id: f7552c4b012ec69cd382c2f8ec5d7e8de888b981
1 parent a2cf506 commit 1997047

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
---
2+
title: How Relay Enables Optimal Data Fetching
3+
author: Jordan Eldredge
4+
tags: []
5+
description:
6+
Exploring the tradoeffs that most data fetching strategies are forced to make,
7+
and how Relay allows you to have your cake and eat it too.
8+
hide_table_of_contents: false
9+
---
10+
11+
Relay’s approach to application authorship enables a unique combination of
12+
optimal runtime performance and application maintainability. In this post I’ll
13+
describe the tradeoffs most apps are forced to make with their data fetching and
14+
then describe how Relay’s approach allows you to sidestep these tradeoffs and
15+
achieve an optimal outcome across multiple tradeoff dimensions.
16+
17+
---
18+
19+
In component-based UI systems such as React, one important decision to make is
20+
where in your UI tree you fetch data. While data fetching can be done at any
21+
point in the UI tree, in order to understand the tradeoffs at play, let’s
22+
consider the two extremes:
23+
24+
- Leaf node: Fetch data directly within each component that uses data
25+
- Root node: Fetch all data at the root of your UI and thread it down to leaf
26+
nodes using prop drilling
27+
28+
Where in the UI tree you fetch data impacts multiple dimensions of the
29+
performance and maintainability of your application. Unfortunately, with naive
30+
data fetching, neither extreme is optimal for all dimensions. Let’s look at
31+
these dimensions and consider which improve as you move data fetching closer to
32+
the leaves, vs. which improve as you move data fetching closer to the root.
33+
34+
### Loading experience
35+
36+
- 🚫 Leaf node: If individual nodes fetch data, you will end up with request
37+
cascades where your UI needs to make multiple request roundtrips in series
38+
(waterfalls) since each layer of the UI is blocked on its parent layer
39+
rendering. Additionally, if multiple components happen to use the same data,
40+
you will end up fetching the same data multiple times
41+
- ✅ Root node: If all your data is fetched at the root, you will make single
42+
request and render the whole UI without any duplicate data or cascading
43+
requests
44+
45+
### Suspense cascades
46+
47+
- 🚫 Leaf node: If each individual component needs to fetch data separately,
48+
each component will suspend on initial render. With the current implementation
49+
of React, unsuspending results in rerendering from the nearest parent suspense
50+
boundary. This means you will have to reevaluate product component code O(n)
51+
times during initial load, where n is the depth of the tree.
52+
- ✅ Root node: If all your data is fetched at the root, you will suspend a
53+
single time and evaluate product component code only once.
54+
55+
### Composability
56+
57+
- ✅ Leaf node: Using an existing component in a new place is as easy as
58+
rendering it. Removing a component is as simple as not-rendering it. Similarly
59+
adding/removing data dependencies can be done fully locally.
60+
- 🚫 Root node: Adding an existing component as a child of another component
61+
requires updating every query that includes that component to fetch the new
62+
data and then threading the new data through all intermediate layers.
63+
Similarly, removing a component requires tracing those data dependencies back
64+
to each root component and determining if the component you removed was that
65+
data’s last remaining consumer. The same dynamics apply to adding/removing new
66+
data to an existing component.
67+
68+
### Granular updates
69+
70+
- ✅ Leaf node: When data changes, each component reading that data can
71+
individually rerender, avoiding the need to rerender unaffected components.
72+
- 🚫 Root node: Since all data originates at the root, when any data updates it
73+
always forces the root component to update forcing an expensive rerender of
74+
the entire component tree.
75+
76+
## Relay
77+
78+
Relay leverages GraphQL fragments and a compiler build step to offer a more
79+
optimal alternative. In an app that uses Relay, each component defines a GraphQL
80+
fragment which declares the data that it needs. This includes both the concrete
81+
values the component will render as well as the fragments (referenced by name)
82+
of each direct child component it will render.
83+
84+
At build time, the Relay compiler collects these fragments and builds a single
85+
query for each root node in your application. Let’s look at how this approach
86+
plays out for each of the dimensions described above:
87+
88+
- ✅ Loading experience - The compiler generated query fetches all data needed
89+
for the surface in a single roundtrip
90+
- ✅ Suspense cascades - Since all data is fetched in a single request, we only
91+
suspend once, and it’s right at the root of the tree
92+
- ✅ Composability - Adding/removing data from a component, including the
93+
fragment data needed to render a child component, can be done locally within a
94+
single component. The compiler takes care of updating all impacted root
95+
queries
96+
- ✅ Granular updates - Because each component defines a fragment, Relay knows
97+
exactly which data is consumed by each component. This lets relay perform
98+
optimal updates where the minimal set of components are rerendered when data
99+
changes
100+
101+
## Summary
102+
103+
As you can see, Relay’s use of a declarative composable data fetching language
104+
(GraphQL), combined a compiler step, allows us to achieve optimal outcomes
105+
across all of the tradeoff dimensions outlined above:
106+
107+
| | Leaf node | Root node | GraphQL/Relay |
108+
| ------------------ | --------- | --------- | ------------- |
109+
| Loading experience | 🚫 |||
110+
| Suspense cascades | 🚫 |||
111+
| Composability || 🚫 ||
112+
| Granular updates || 🚫 ||

0 commit comments

Comments
 (0)