Qu'est-ce que Qora ?
Qora est une bibliothèque de state serveur pour Flutter et Dart. Elle récupère, met en cache et synchronise les données que votre application charge depuis une API, et garde l'application utilisable quand le réseau ne l'est pas.
Si vous connaissez TanStack Query, vous connaissez déjà le modèle : les données serveur sont un cache avec un cycle de vie, pas un state global d'UI. Qora apporte ce modèle à Dart 3 avec les sealed classes et le pattern matching, sans génération de code.
Le problème résolu
Une donnée qui vient d'un serveur n'est pas un compteur ni un champ de formulaire. Elle peut être périmée, elle est partagée entre plusieurs écrans, elle change quand quelqu'un écrit dessus, et elle disparaît avec le réseau. Gérée à la main, chaque écran finit avec le même code :
class _UserScreenState extends State<UserScreen> {
User? _user;
Object? _error;
bool _loading = false;
@override
void initState() {
super.initState();
_load();
}
Future<void> _load() async {
setState(() => _loading = true);
try {
_user = await api.getUser(widget.userId); // re-téléchargé à chaque visite
_error = null;
} catch (e) {
_error = e; // et l'utilisateur précédent est perdu en cas d'erreur
} finally {
setState(() => _loading = false);
}
}
// ...et rien ne rafraîchit cet écran quand un autre modifie l'utilisateur.
}
Avec Qora, l'écran déclare de quelles données il a besoin et comment afficher chaque état :
QoraBuilder<User>(
queryKey: ['users', userId],
fetcher: () => api.getUser(userId),
builder: (context, state, fetchStatus) => switch (state) {
Success(:final data) => UserCard(data),
Failure(:final error, :final previousData) =>
previousData != null ? UserCard(previousData) : ErrorView(error),
Loading(:final previousData) =>
previousData != null ? UserCard(previousData) : const LoadingView(),
Initial() => const SizedBox.shrink(),
},
)
À la deuxième visite, l'utilisateur en cache s'affiche dès la première frame et se rafraîchit en arrière-plan. Deux widgets qui demandent ['users', userId] partagent une seule requête. Après client.invalidate(['users', userId]), chaque écran qui affiche cet utilisateur se met à jour. Le compilateur vérifie que chaque état est traité.
Ce que vous obtenez
Récupération et cache
- Stale-while-revalidate : les données du cache d'abord, les données fraîches en arrière-plan
- Déduplication des requêtes et retries automatiques avec backoff exponentiel
- Invalidation par clé exacte, préfixe de clé, prédicat ou tag
- Requêtes infinies, requêtes dépendantes, polling, prefetch
Hors-ligne
PersistQoraClient: données du cache sauvegardées et restaurées avant la première frame- Des requêtes qui se mettent en pause hors-ligne, le signalent via
FetchStatus.pausedet reprennent à la reconnexion - Une file de mutations hors-ligne qui rejoue les écritures dans l'ordre au retour du réseau (en mémoire ; persistée entre deux redémarrages en 1.4)
Écritures
- Mutations avec
onMutate/onError/onSuccesspour les mises à jour optimistes et le rollback - Invalidation automatique après une mutation réussie
Outillage
- Un overlay DevTools dans l'application qui affiche chaque requête et chaque mutation en mode debug
Packages
| Package | À utiliser pour |
|---|---|
qora_flutter | Les apps Flutter. Widgets (QoraScope, QoraBuilder, QoraMutationBuilder, InfiniteQueryBuilder), managers de cycle de vie et de connectivité. Inclut qora. |
qora_hooks | Les apps qui utilisent flutter_hooks : useQuery, useMutation, useInfiniteQuery, useFetchStatus. |
qora | Dart pur : CLI, serveurs, packages partagés, tests. Aucune dépendance Flutter. |
qora_devtools_overlay | Le panneau de debug dans l'application, en dépendance de développement. |
State serveur et state client
Qora gère le state serveur : les données qui vivent sur un serveur et qui sont récupérées, mises en cache et resynchronisées. Il ne remplace pas votre state management pour le state client : l'onglet sélectionné, la saisie d'un formulaire, le thème. Gardez Riverpod, BLoC ou Provider pour cela ; les guides d'intégration montrent comment les combiner.
Quand ne pas utiliser Qora
- Une application en lecture seule, toujours en ligne, qui n'affiche jamais deux fois les mêmes données. Un
FutureBuildersuffit. - Des données temps réel poussées par une socket. Vous pouvez écrire les événements de la socket dans le cache avec
setQueryData, mais le flux lui-même n'est pas le rôle de Qora.
Pour une comparaison avec cached_query et flutter_query, voir la page de comparaison.
Prérequis
- Dart 3.5 ou plus récent
- Flutter 3.24 ou plus récent (pour
qora_flutteretqora_hooks)
Étapes suivantes
- Installation : ajouter Qora et envelopper votre application
- Démarrage rapide : un écran liste et un écran détail, puis le passage hors-ligne
- Venir de TanStack Query : l'API mise en correspondance option par option