Let’s say we have a component tree in react
<Tree>
<TreeTrunkDetails/>
<TreeLeavesDetails/>
</Tree>
and a useTree hook that wraps a useQuery hook that fetches something like
tree {
specie
genus
leaves {
shape
size
}
trunk {
bark
diameter
}
}
We could call useTree
in <Tree>
and then pass trunk and leaves data to <TreeLeavesDetails details={leaves}/>
and <TreeTrunkDetails details={trunk}/>
respectively.
We could also hook <Tree>
and <TreeLeavesDetails/>
and <TreeTrunkDetails/>
with the same useTree
hook. Given that results will be cached in the client (assuming we can cache) the performance will be ok
Or we could create a useTree
, useTreeTrunk
and a useTreeLeaves
hooks and the hook each component with its specific hook (and query requesting only the data it needs).
What pattern is recommended by the Apollo team?
Thank you
2 Likes
It’s a good question. Personally I’m finding performance issues when I’m using too many instances of useQuery
(in the 100s or 1000s).
I haven’t found a great way to improve the performance here other than to use less useQuery
s and use more contexts/props.
1 Like
There’s a new hook coming in v3.7 called useFragment
which may make this easier: Feature: useFragment hook · Issue #8236 · apollographql/apollo-client · GitHub
Has anyone found a way to improve this pattern using useFragment
now that it’s available?
Hi @swrobel! I recommend checking out our Spotify Showcase for an up-to-date view of some best practices for using Apollo Client in 2024. It includes useFragment
usage and other new APIs.
I’ve heard of some Apollo Client users taking this one step further and using the Relay compiler with Apollo Client to compose queries from fragments, but that’s not a workflow we officially support. Does that help?
1 Like
I suppose it helps in the sense that it clarifies that Apollo still doesn’t have the capability to compose queries from fragments automatically, which was an open question for me. I doubt we would go so far as to bring the Relay compiler in to bridge this gap.
@swrobel you might be interested in the fragment registry which allows you to define fragments and reference them by name without having to use the interpolation syntax. It’s not quite what the Relay compiler does, but since Apollo doesn’t use a compiler, this is as close as you can get. You just need to ensure the fragment is registered in the fragment registry before the query is run in order for this to work.
The Spotify showcase has some examples of registering fragments defined in components then referencing them by name in your queries.
Hope this works for you!
1 Like
Here is an example of the fragment registry in action.
AlbumTile
registers a fragment with the registry which is then used by the route query by name.
1 Like
Thanks so much for the replies! I’ve read the comments in useSavedTracksContains several times, and I still don’t understand the pattern of utilizing useBackgroundQuery
and useFragment
in the same file. Is the useFragment
basically there to read all of the batches present in the cache as they come in?
I’ll admit, that one is a bit of an odd duck but I can provide some context there (and perhaps this is a good opportunity for me to update the comments to make it even clearer!)
The idea behind that hook is that if I have a large playlist, I want to be able to determine which of those playlist items are actually “liked”. Spotify’s API only allows us to load 50 items at a time, so large playlists present a problem because I need to slice up the list of ids into 50-length batches and request those.
useBackgroundQuery
is doing the work to load the initial 50 items because I want to kick that off in render rather than useEffect
, then I load the rest of the batches via client.query(...)
. The useFragment
is there to handle cache updates so that I can return the entire set of results without having to sync that state to my own useState
(potentially getting out of sync). This is also useful in case I already have that data in the cache as I don’t need to run my own cache.readFragment
to get the initial set of results.
To be honest, I’m not entirely sure if useBackgroundQuery
is necessary here, and as I’m thinking about this, its auto dispose behavior may actually work against me. I’ll need to explore that a bit more.
Hope this helps provide some context!
1 Like