QoraScope
QoraScope is the single point of truth for your QoraClient in Flutter. Wrap your app (or a sub-tree) with it once, and every descendant gains access to the same cache and request pipeline.
Anatomy
Default constructor
QoraScope(
// Required: the shared cache and request engine
client: client,
// Optional: invalidates queries on app resume
lifecycleManager: FlutterLifecycleManager(qoraClient: client),
// Optional: pure signal provider for network connectivity
connectivityManager: FlutterConnectivityManager(),
child: const MyApp(),
)
QoraScope.auto()
A convenience constructor that wires both managers automatically:
QoraScope.auto(
client: QoraClient(),
child: const MyApp(),
)
// Equivalent to passing FlutterLifecycleManager + FlutterConnectivityManager manually.
// Disable specific listeners:
QoraScope.auto(
client: QoraClient(),
enableLifecycle: false,
enableConnectivity: false,
child: const MyApp(),
)
QoraScope is a StatefulWidget. It calls start() on each manager in initState and calls dispose() on both managers and on the client itself in dispose. You never manage their lifetime manually.
Accessing the Client
context.qora (recommended)
The shortest path to the client from any widget:
// Invalidate a specific query after a mutation
context.qora.invalidate(['posts', postId]);
// Invalidate by predicate
context.qora.invalidateWhere((key) => key.firstOrNull == 'posts');
// Optimistic update
final snapshot = context.qora.getQueryData<User>(['users', userId]);
context.qora.setQueryData(['users', userId], updatedUser);
QoraScope.of(context)
Equivalent to context.qora. Throws a descriptive FlutterError if no QoraScope ancestor is found in the tree:
final client = QoraScope.of(context);
await client.fetchQuery<List<Post>>(
key: ['posts'],
fetcher: api.getPosts,
);
QoraScope.maybeOf(context)
Returns null instead of throwing when QoraScope is absent. Useful when the scope is optional in part of the tree:
final client = QoraScope.maybeOf(context);
if (client == null) return const SizedBox.shrink();
context.qoraOrNull
Shorthand for QoraScope.maybeOf(context):
context.qoraOrNull?.invalidate(['notifications']);
Nested Scopes
You can nest multiple QoraScope widgets to isolate caches for different parts of the app: for example, separate caches for public and authenticated routes:
QoraScope(
client: publicClient,
child: Navigator(
pages: [
MaterialPage(child: const HomeScreen()),
MaterialPage(
child: QoraScope(
// Separate cache for authenticated routes
client: authClient,
child: const DashboardScreen(),
),
),
],
),
)
Each QoraScope manages its own client: queries are fully independent between scopes.
Lifecycle and Connectivity Managers
FlutterLifecycleManager
Observes AppLifecycleState changes via WidgetsBindingObserver. When the app resumes after a pause longer than minBackgroundDuration, it calls client.invalidateWhere((_) => true):
FlutterLifecycleManager(
qoraClient: client,
minBackgroundDuration: const Duration(minutes: 1), // default: 5 s
)
Active QoraBuilder widgets receive the resulting Loading(previousData: data) state and immediately dispatch re-fetch requests. Users see the stale data instantly while fresh data loads in the background.
FlutterConnectivityManager
A pure signal provider: it converts connectivity_plus events into NetworkStatus values and nothing else. QoraScope wires it to the client automatically via attachConnectivityManager() after calling start().
All reconnect logic (query replay, offline mutation queue replay, thundering-herd batching) runs inside QoraClient, not inside the manager:
// No QoraClient reference required: pure signal provider
FlutterConnectivityManager()
Requires connectivity_plus in your pubspec.yaml:
dependencies:
connectivity_plus: ^6.0.0
FlutterConnectivityManager no longer invalidates queries directly. Reconnect behaviour is controlled by QoraClientConfig.reconnectStrategy and per-query QoraOptions.networkMode. Implement a custom ConnectivityManager if you need to source connectivity events from a different package.Accessing the ConnectivityManager from descendants
QoraScope.connectivityManagerOf(context) exposes the manager to widgets deeper in the tree (used internally by NetworkStatusBuilder):
final manager = QoraScope.connectivityManagerOf(context);
final status = manager?.currentStatus ?? NetworkStatus.unknown;
API Reference
| Property / Method | Type | Description |
|---|---|---|
client | QoraClient | Required. The shared client for this scope. |
lifecycleManager | LifecycleManager? | Optional. Refetch on app resume. |
connectivityManager | ConnectivityManager? | Optional. Pure signal provider: no QoraClient ref needed. |
child | Widget | Required. The widget subtree. |
QoraScope.auto() | Constructor | Shorthand that wires FlutterLifecycleManager + FlutterConnectivityManager. Accepts enableLifecycle, enableConnectivity, minBackgroundDuration. |
QoraScope.of(context) | QoraClient | Returns the client; throws if none found. |
QoraScope.maybeOf(context) | QoraClient? | Returns the client, or null if none found. |
QoraScope.connectivityManagerOf(context) | ConnectivityManager? | Returns the active manager; used by NetworkStatusBuilder. |
context.qora | QoraClient | Shorthand for QoraScope.of(context). |
context.qoraOrNull | QoraClient? | Shorthand for QoraScope.maybeOf(context). |
Next Steps
- QoraBuilder: Fetch data and bind state to Flutter widgets
- Network Status:
NetworkStatusBuilderandNetworkStatusIndicatorwidgets - Network Aware Guide: Full offline-first setup walkthrough
- Quick Start: End-to-end Flutter integration walkthrough