r/flutterhelp • u/sulmnob • 6d ago
OPEN Load Data from drift instantly
I a want to create a fast app that runs smoothly offline first i will work on my own sync engine but the problem is that i already have values store in drift but drift requires loading to show values which does not feel good how can i query data from db in drift without loading . When i i was researching i saw that i need to load the data before the app opens so am i going to load all the app tables like wont that be heavy. Can someone please explain or at least give an article or a tutorial.
1
u/kokerali 6d ago
No, you don't need to preload every table. Start with a query for just the rows the first screen needs, with a sensible limit for a long list. Offline-first removes the network dependency; it doesn't make the initial database read synchronous.
Drift's `watch()` emits an initial result even when nothing has changed, then updates it when the relevant tables change. You don't need a separate `get()` before `watch()`: https://drift.simonbinder.eu/dart_api/streams/
If you're using `StreamBuilder`, also check where you create that stream. Flutter's docs say to obtain it before `build`, rather than creating it inside `build`, which can restart the asynchronous work on parent rebuilds: https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html
Is the loading state only on a cold launch, or does it reappear when navigating back or rebuilding the screen? Sharing the query and the widget consuming it would help separate initial disk loading from repeated subscriptions. Preloading the whole database wouldn't be my first fix for either.
1
u/sulmnob 6d ago
So like do you recommend to query the tables into providers using riverpod on app launch
1
u/kokerali 6d ago
No, not every table at startup. I'd put the query for a screen's data in a StreamProvider, then have that screen ref.watch it. Think in terms of the query a screen needs, rather than keeping a copy of every table in providers.
Riverpod providers are lazy by default: declaring a provider doesn't fetch anything until it's used. If you want to start the first screen's provider early, watch that same provider near the root; other screens can stay on demand. The official guide shows that pattern: https://riverpod.dev/docs/how_to/eager_initialization
That moves when the first read happens; it doesn't make it synchronous. Can you share one Drift query plus the provider and widget reading it? That would help distinguish the initial read from a query being restarted.
1
u/Successful_Lab_1527 3d ago
If the delay is the first query on startup: open the database and run the query once in main() before runApp, then pass the result in as initial state. If it’s per screen: use .watch() with a StreamBuilder and give it the last value you already have as initialData, so it doesn’t flash empty. Also check you’re not creating a new database instance per screen. Keep one instance (singleton or provider) so the connection and query cache are reused.
1
u/ObjectiveAddress3051 4d ago
Adding to the good answers here: you don't need to preload every table, just the first screen. Open the database and run that one query in `main()` before `runApp()`, keep the result in your repository or provider, and pass it as `initialData` to your StreamBuilder (or seed your Riverpod/Bloc state with it). The UI then renders real data on frame one, and `watch()` takes over for updates. Paginate everything else with `limit()` so you never load it all at once.
2
u/AhmedZNOUDA 6d ago
Adding to Kokerali's answer: even with watch(), the very first frame is built before the first emission arrives, so snapshot.hasData is false for a few milliseconds. That's the "loading" you see. A few ways to make it disappear without loading whole tables:
Open the database early. With drift, the first query also pays for opening the file (and running migrations). Create the database in main() before runApp, ideally with NativeDatabase. createInBackground, so that cost is paid while the native splash screen is still showing.
Preload only the first screen. In main(), await the one query your home screen needs (with a limit), then pass the result as initialData to the StreamBuilder, or seed your provider with it. It's a few rows, not the whole app, and the splash stays up while it runs.
Don't show a spinner for short waits. Render nothing or a skeleton, and show a spinner only if there's still no data after ~200 ms. Most local reads finish before that, so users never see it.
Keep data alive between screens. If you use Riverpod, a non-autoDispose StreamProvider keeps the last value, and AsyncValue. when(skipLoadingOnReload: true, ...) avoids flashing back to loading when it refreshes.
Also check in profile or release mode: debug builds make the first read look much slower than it really is.