so, let's say I have a "master/detail"-ish architecture, where my UI has a section for a specific user, and within that section is a page that shows that user's followers. it's at a route like /users/:username/followers
.
in my component hierarchy, this works with something like
<FollowersPage> <-- top level route component, matched by react-router
<UserSectionWrapper> <-- renders the outer wrapper for the user section
<FollowersList /> <-- the inner content of the page
</UserSectionWrapper>
</FollowersPage>
<UserSectionWrapper />
renders some basic information about a user, such as their display name and avatar. <FollowersList />
renders the list of their followers.
Now, how I was hoping to structure this, using GraphQL, was to have <UserSectionWrapper />
wrapped with a higher-order GraphQL component:
const userQuery = gql`
query User($username: String!) {
user(username: $username) {
id
displayName
avatar
}
}
`;
const withUser = graphql<any, Props>(userQuery, {
options: (props: Props) => {
return {
variables: {
username: props.username,
},
};
},
});
And also wrap <FollowersList />
in a similar HOC:
const followersQuery = gql`
query Followers($username: String!) {
user(username: $username) {
followers {
id
username
displayName
}
}
}
`;
const withFollowers = graphql<any, Props>(followersQuery, {
options: (props: Props) => {
return {
variables: {
username: props.username,
},
};
},
});
However, the problem with this is that it makes a separate GraphQL request for each component. This is bad.
So, my assumption is that I need to move the queries into the top-level <FollowersPage/ >
. Then, I can either pass down the data into my component tree, or continue using the HoCs as-written and just rely on the Apollo cache to avoid remaking the requests.
So, what's the best way to structure this? Can I write, like, a UserSectionWrapper
query, and a FollowersList
query, and then combine them into a FollowersPage
query? Is this what "fragments" are for? The Apollo docs are confusing on this (I think partially because it assumes I have a greater understanding of GraphQL than I do).
followup question on caching:
what's up with apollo's cache operating at the "query" level, and not at, like, an entity level? it kinda makes my plan of "the top-level component provides the entire page's data" worse when now, when navigating between pages, it always has to re-query all data, since there is no shared cached knowledge.
as a concrete example, given my previous gist: if I have a
/users/thomas/followers
page, and a/users/thomas/following
page, and they each have these queries:When I navigate from /followers to /following, Apollo doesn't know that the id/displayName/avatar are the same, and re-queries them.
this isn't a huge deal from a performance perspective, but is bad from a UI perspective: when I navigate from /followers to /following, I want to continue showing a UI using state about the user while loading the next screen, and currently, I have no way to access that state while loading, since it's not cached under the same query.