Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POC: Suspense for usePowerSyncWatchedQuery #100

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft

Conversation

rkistner
Copy link
Contributor

@rkistner rkistner commented Mar 18, 2024

This is an alternative approach to #84 - see the PR for the problem statement.

This uses React <Suspense> to wait until the initial query results have loaded before rendering the component. This makes the usePowerSyncWatchedQuery API practically unchanged: Just use const results = usePowerSyncWatchedQuery(...) - but without ever getting "loading" results. Instead, you use Suspense and error boundaries to handle loading states and errors, respectively.

The changes to the demo app are primarily:

  1. Refactor sql-console page to handle loading and error states.
  2. Refactor todo list page to display the list of todos to the left and todos on the right (same as POC: Preloading queries #84).
  3. Place <Suspense/> in the layout.

One caveat is that, by default, you now get a loading spinner (the Suspense fallback) for an instant when navigating. useTransition avoids this, but it's tedious to add to every navigation, and that doesn't handle browser back/forward. Ideally this would be handled by the router, but integrating this with react-router seems tricky. Update: react-router has an experimental option v7_startTransition that does exactly this.

The implementation is based on Relay's useLazyLoadQuery implementation. This approach is called "fetch-on-render", which is typically not recommended for fetching data from a server, since it often causes "waterfall" loading. However, loading from a local database is very fast despite it being asynchronous, so that's not really an issue.

React does make it difficult to implement this pattern. When "suspending" a render, all state is discarded, so you can't keep track of a loading query in the component state. Instead, a "QueryStore" is used here to keep track of watched queries. It uses some workarounds to track queries between the initial suspend and the first actual render. One additional advantage of this approach is that watched queries can now be shared between different components, instead of each re-evaluating the same queries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant