I am new to using Relay and wondering how it is best to structure when a new query is required further down the DOM tree.
Relay provides a great guide to writing queries, which suggests to have a very limited number of queries and to compose the data you need using fragments. I totally agree with this approach however haven't found a great way of using this flow when different queries are needed at varying levels of the DOM tree.
For example:
- On the root of the app I query for the user data
- The direct children of the root define which user data they need using fragments
- A child way further down the tree (say 5+ levels deep) needs address information which is available via a different query (eg so that they have state/country options to edit their address)
I often find situations like the above example in two scenarios:
- There is an interaction that causes it the address data be required (eg they press "edit address"), in this case use the "render-as-you-fetch" pattern to make a new query to fetch the data
- The address information is always going to be required so it should be fetched with the user query
The first scenario is straight forward as it makes sense to have this as a separate query. However, in the second scenario is where I find I often run into the same two problems:
- Adding the queries to the root query and passing down the data via props quickly becomes unpractical when the DOM tree is deep or complicated.
- Having multiple queries often leads to a waterfall of loaders and additional wait time, this is annoying as this could be avoided by querying all of the data at once.
Another semi-unrelated situation where I find this comes up is if there is additional queries I need to make in a component that is using a fragment. For example I have a list of items, in the item component I have a fragment defined to declare the data I need for an item, however I also need to get other data via a new query. Ideally it'll be nice to add this additional query to my fragment.
One solution I occasionally use is to run all of the queries at the root level and feed their data into a context, which I then consume in the apps that need it. While this does work, it doesn't follow the idea of colocation which Relay promotes, I would prefer to see the data next to the component that is uses it.
Potentially something like this would be better:
query UserQuery {
getUser(id: "aaa") {
name
...UserProfile_user
...UserAddress_user
}
...AddressQuery
}
query AddressQuery {
queryAddress {
state {
id
name
}
country {
id
name
}
}
}
Where the AddressQuery
would live in the component that is consuming that data. Understanding that this approach would very likely result incasing down the data via props to this child, or use the pattern of passing the data into a context (as mentioned before).
Am I missing something obvious about combining GraphQL queries? Is there a better way to solve this problem?