Preloading
Almost all Zero apps will want to preload some data in order to maximize the “local-first” feel of instantaneous UI transitions.
In Zero, preloading is done via queries – the same queries you use in the UI and for auth.
However, because preload queries are usually much larger than a screenful of UI, Zero provides a special preload()
helper to avoid the overhead of materializing the result into JS objects:
// Preload the first 1k issues + their creator, assignee, labels, and
// the view state for the active user.
//
// There's no need to render this data, so we don't use `useQuery()`:
// this avoids the overhead of pulling all this data into JS objects.
z.query.issue
.related('creator')
.related('assignee')
.related('labels')
.related('viewState', q => q.where('userID', z.userID).one())
.orderBy('created', 'desc')
.limit(1000)
.preload();
Consistency
Currently, Zero does not have any special consistency logic implemented. Each query runs against local data, and in parallel against server data.
Without some care, this can lead to undesirable flickering in the UI.
Imagine that you have a bug database w/ 10k issues. You preload the first 1k issues sorted by created.
The user then does a query of issues assigned to themselves, sorted by created. Among the 1k issues that were preloaded there will be some assigned to the user. Since the data we preloaded is in the same order as this query, we are guaranteed that any local results will be a prefix of the server results. The UX result is that the user will see some data locally instantly. If it’s not a complete screenful of data, then the server result will fill in asynchronously, but any new data from server will be at the bottom of the already displayed results. The user won’t see any weird reshuffling of results when the server result comes in.
Now imagine that the user switches the sort to ‘sort by modified’. This new query will run locally, and will again find some matches. But it is unlikely that the local results are a prefix of the server results. When the server result comes in, it is highly likely the user will see the results shuffle.
To avoid this problem today, what you should do is preload the first n
results of every query you intend to do in list views of your app. This ensures that when the app goes to do that query there is already a preloaded result for the first bit of it.
Future
For Zero Beta, we will be implementing a consistency model that fixes this. We will prevent Zero from returning local data when that data is not known to be a prefix of the server result. Once the consistency model is implemented, preloading can be thought of as purely a performance thing, and not required to avoid unsightly flickering.
Examples
zbugs preloads all issues, their labels, and first ten comments:
https://github.com/rocicorp/mono/blob/main/apps/zbugs/src/zero-setup.ts#L43