centralized vs. decentralized client data
question (and maybe I shouldn't worry about this :lul: but I'm curious): if I return an OmegaObject™️ from a query that contains a doc and all of its related docs, does convex make efficient patch updates for that query on change? or is it more efficient to use separate queries still, so that only relevant queries get updated
also, generally speaking, which should I prefer: fewer query calls higher up the react tree, or more query calls closer to leaves of the tree? I imagine that depends on the UX you want, but I wonder if there are other factors to consider
4 Replies
i actually went and thought this out myself, and it seems like I should prefer centralized for my use case at least, popcorn loading spinners and waterfalls aren't great
some of this changes with suspense and preloading, but I'm using remix, and I don't feel like figuring that out :akkoShrug:
---
Centralized
Pros
- All data needed for the view is loaded upfront in parallel
- One or a few big pending states
Cons
- Loading data you may not need
- Requires either lots of prop passing or context
- Larger rerenders on updates
Decentralized
Pros
- Data is loaded on an as-needed basis
- No need for frequent passing of props or context in most cases
- More granular rerenders
Cons
- Waterfalls are pretty much guaranteed
- More tedious null checks on result data
- More popcorning loading spinners
- Unmounting and remounting of queries creates more function calls towards quota usage (?)
I'd add to the Centralized Cons that it can lead to oversubscription: Unrelated writes will cause the whole centralized query to update.
Right now you have to judge this tradeoff for yourself in your app.
Also you can avoid popcorning with React Suspense.
To avoid coarse subscription you can register the smaller queries in the upper component, using useQueries. You can then make the same subscriptions lower down and they’ll use the local cache
Some things are hard to get around the waterfalls for, though. For lists, managing oversubscription with pagination works pretty well.
This is actually kinda of the pattern I've implemented in convex-vue to add remix-style loaders on a route by route basis: before navigating to the page, some subscriptions are fired but the result is not consumed yet, however the cache is fresh, or at least close to having results when the page s displayed.
There are also interesting patterns you could do like start "prefetching" queries when hovering links, or when some piece of UI is about to enter the viewport, etc