Usage avec Flutter

QoraScope

Le StatefulWidget qui fournit un QoraClient à l'arbre de widgets et gère le cycle de vie des gestionnaires de plateforme optionnels.

QoraScope est le point de vérité unique pour le QoraClient dans Flutter. Encapsuler l'application (ou un sous-arbre) avec ce widget une seule fois, et chaque descendant accède au même cache et au même pipeline de requêtes.


Anatomie

Constructeur par défaut

main.dart
QoraScope(
  // Requis : le cache partagé et le moteur de requêtes
  client: client,

  // Optionnel : invalide les requêtes à la reprise de l'application
  lifecycleManager: FlutterLifecycleManager(qoraClient: client),

  // Optionnel : fournisseur de signal pur pour la connectivité réseau
  connectivityManager: FlutterConnectivityManager(),

  child: const MyApp(),
)

QoraScope.auto()

Un constructeur pratique qui câble automatiquement les deux gestionnaires :

main.dart
QoraScope.auto(
  client: QoraClient(),
  child: const MyApp(),
)
// Équivalent à passer manuellement FlutterLifecycleManager + FlutterConnectivityManager.

// Désactiver des listeners spécifiques :
QoraScope.auto(
  client: QoraClient(),
  enableLifecycle: false,
  enableConnectivity: false,
  child: const MyApp(),
)

QoraScope est un StatefulWidget. Il appelle start() sur chaque gestionnaire dans initState et appelle dispose() sur les deux gestionnaires et sur le client lui-même dans dispose. Le cycle de vie n'est jamais géré manuellement.


Accéder au client

context.qora (recommandé)

Le chemin le plus court vers le client depuis n'importe quel widget :

user_list_screen.dart
// Invalider une requête spécifique après une mutation
context.qora.invalidate(['posts', postId]);

// Invalider par prédicat
context.qora.invalidateWhere((key) => key.firstOrNull == 'posts');

// Mise à jour optimiste
final snapshot = context.qora.getQueryData<User>(['users', userId]);
context.qora.setQueryData(['users', userId], updatedUser);

QoraScope.of(context)

Équivalent à context.qora. Lève une FlutterError descriptive si aucun ancêtre QoraScope n'est trouvé dans l'arbre :

user_repository.dart
final client = QoraScope.of(context);
await client.fetchQuery<List<Post>>(
  key: ['posts'],
  fetcher: api.getPosts,
);

QoraScope.maybeOf(context)

Retourne null au lieu de lever une exception quand QoraScope est absent. Utile quand le scope est optionnel dans une partie de l'arbre :

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

context.qoraOrNull

Raccourci pour QoraScope.maybeOf(context) :

nav_bar.dart
context.qoraOrNull?.invalidate(['notifications']);

Scopes imbriqués

Plusieurs widgets QoraScope peuvent être imbriqués pour isoler les caches dans différentes parties de l'application : par exemple, des caches séparés pour les routes publiques et authentifiées :

app.dart
QoraScope(
  client: publicClient,
  child: Navigator(
    pages: [
      MaterialPage(child: const HomeScreen()),
      MaterialPage(
        child: QoraScope(
          // Cache séparé pour les routes authentifiées
          client: authClient,
          child: const DashboardScreen(),
        ),
      ),
    ],
  ),
)

Chaque QoraScope gère son propre client : les requêtes sont entièrement indépendantes entre les scopes.


Gestionnaires de cycle de vie et de connectivité

FlutterLifecycleManager

Observe les changements d'AppLifecycleState via WidgetsBindingObserver. Quand l'application reprend après une pause supérieure à minBackgroundDuration, il appelle client.invalidateWhere((_) => true) :

main.dart
FlutterLifecycleManager(
  qoraClient: client,
  minBackgroundDuration: const Duration(minutes: 1), // défaut : 5 s
)

Les widgets QoraBuilder actifs reçoivent l'état Loading(previousData: data) résultant et déclenchent immédiatement des requêtes de refetch. Les utilisateurs voient les données périmées instantanément pendant que les données fraîches se chargent en arrière-plan.

FlutterConnectivityManager

Un fournisseur de signal pur : il convertit les événements connectivity_plus en valeurs NetworkStatus uniquement. QoraScope le câble automatiquement au client via attachConnectivityManager() après l'appel de start().

Toute la logique de reconnexion (relecture des requêtes, relecture de la file de mutations hors-ligne, traitement par lots du thundering-herd) s'exécute dans QoraClient, et non dans le gestionnaire :

main.dart
// Pas de référence QoraClient requise : fournisseur de signal pur
FlutterConnectivityManager()

Nécessite connectivity_plus dans pubspec.yaml :

pubspec.yaml
dependencies:
  connectivity_plus: ^6.0.0
FlutterConnectivityManager n'invalide plus les requêtes directement. Le comportement de reconnexion est contrôlé par QoraClientConfig.reconnectStrategy et QoraOptions.networkMode par requête. Implémenter un ConnectivityManager personnalisé pour sourcer les événements de connectivité depuis un package différent.

Accéder au ConnectivityManager depuis les descendants

QoraScope.connectivityManagerOf(context) expose le gestionnaire aux widgets plus profonds dans l'arbre (utilisé en interne par NetworkStatusBuilder) :

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

Référence API

Propriété / MéthodeTypeDescription
clientQoraClientRequis. Le client partagé pour ce scope.
lifecycleManagerLifecycleManager?Optionnel. Refetch à la reprise de l'application.
connectivityManagerConnectivityManager?Optionnel. Fournisseur de signal pur : pas de référence QoraClient requise.
childWidgetRequis. Le sous-arbre de widgets.
QoraScope.auto()ConstructeurRaccourci qui câble FlutterLifecycleManager + FlutterConnectivityManager. Accepte enableLifecycle, enableConnectivity, minBackgroundDuration.
QoraScope.of(context)QoraClientRetourne le client ; lève une exception si absent.
QoraScope.maybeOf(context)QoraClient?Retourne le client, ou null si absent.
QoraScope.connectivityManagerOf(context)ConnectivityManager?Retourne le gestionnaire actif ; utilisé par NetworkStatusBuilder.
context.qoraQoraClientRaccourci pour QoraScope.of(context).
context.qoraOrNullQoraClient?Raccourci pour QoraScope.maybeOf(context).

Étapes suivantes

Copyright © 2026