Flutter Integration

QoraScope

The StatefulWidget that provides a QoraClient to your widget tree and manages the lifecycle of optional platform managers.

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

main.dart
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:

main.dart
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

The shortest path to the client from any widget:

user_list_screen.dart
// 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:

user_repository.dart
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:

optional_widget.dart
final client = QoraScope.maybeOf(context);
if (client == null) return const SizedBox.shrink();

context.qoraOrNull

Shorthand for QoraScope.maybeOf(context):

nav_bar.dart
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:

app.dart
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):

main.dart
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:

main.dart
// No QoraClient reference required: pure signal provider
FlutterConnectivityManager()

Requires connectivity_plus in your pubspec.yaml:

pubspec.yaml
dependencies:
  connectivity_plus: ^6.0.0
The 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):

lib/ui/offline_badge.dart
final manager = QoraScope.connectivityManagerOf(context);
final status = manager?.currentStatus ?? NetworkStatus.unknown;

API Reference

Property / MethodTypeDescription
clientQoraClientRequired. The shared client for this scope.
lifecycleManagerLifecycleManager?Optional. Refetch on app resume.
connectivityManagerConnectivityManager?Optional. Pure signal provider: no QoraClient ref needed.
childWidgetRequired. The widget subtree.
QoraScope.auto()ConstructorShorthand that wires FlutterLifecycleManager + FlutterConnectivityManager. Accepts enableLifecycle, enableConnectivity, minBackgroundDuration.
QoraScope.of(context)QoraClientReturns 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.qoraQoraClientShorthand for QoraScope.of(context).
context.qoraOrNullQoraClient?Shorthand for QoraScope.maybeOf(context).

Next Steps

Copyright © 2026