Prise en main

Venant de TanStack Query

Correspondance précise des concepts, hooks et options de configuration de TanStack Query vers leurs équivalents Qora. Couvre ce qui est identique, ce qui est renommé et ce qui fonctionne différemment.

Qora partage le même modèle conceptuel que TanStack Query : clés de requête, stale-while-revalidate, refetch en arrière-plan, hooks de cycle de vie des mutations et pause-et-replay hors-ligne. La plupart des concepts se traduisent directement. Cette page met en correspondance ce que vous connaissez déjà avec l'API Qora.


Correspondance des concepts

Concept TanStack QueryÉquivalent Qora
QueryClientQoraClient
QueryClientProviderQoraScope
useQueryQoraBuilder<T> (widget) ou useQuery<T> (hook)
useMutationQoraMutationBuilder (widget) ou useMutation (hook)
useInfiniteQueryInfiniteQueryBuilder (widget) ou useInfiniteQuery (hook)
useQueryClientcontext.qora / useQueryClient() (hook)
useIsFetchinguseIsFetching() (hook) ou client.fetchingCountStream
useIsMutatinguseIsMutating() (hook) ou client.activeMutations
QueryObserverclient.watchQuery<T> / InfiniteQueryObserver
persistQueryClientPersistQoraClient
DevToolsqora_devtools_overlay (in-app)

Référence API : requêtes

Options

Option TanStack QueryÉquivalent QoraNotes
queryKeyqueryKeyMême concept. TanStack utilise des tableaux ; Qora utilise List<dynamic>. Égalité structurelle dans les deux.
queryFnfetcherMême rôle. Renommé.
enabledenabledIdentique.
staleTimestaleTimeIdentique. Duration.zero = toujours périmé.
gcTime (cacheTime en v4)gcTimeDésormais identique à la v5.
retryretryCountRenommé. Valeur par défaut 3 dans les deux.
retryDelayretryDelay / retryDelayCalculatorBackoff exponentiel par défaut. retryDelayCalculator accepte une fonction recevant l'index de tentative.
refetchOnWindowFocusrefetchOnWindowFocusIdentique. Nécessite FlutterLifecycleManager.
refetchOnReconnectrefetchOnReconnectIdentique. Nécessite FlutterConnectivityManager.
refetchOnMountrefetchOnMountSémantique identique. null hérite de QoraClientConfig.refetchOnMount.
refetchIntervalrefetchIntervalIdentique. Actif tant qu'au moins un abonné est présent.
networkModenetworkModeMême nom, mêmes trois valeurs : online, always, offlineFirst.
selectselect (filtre de rebuild) / transform / state.map()Sémantique différente, voir plus bas.
placeholderDataplaceholderDataUne fonction qui renvoie un placeholder, par exemple depuis une autre requête en cache.
placeholderData: keepPreviousDatapreviousData sur Loading / Failure, ou keepPreviousData: truepreviousData est toujours présent. keepPreviousData garde l'entrée en Success pendant un refetch.
initialDatainitialDataInjecté avant la première frame. client.hydrateQuery<T>(key, data) fait la même chose de façon impérative.
initialDataUpdatedAtinitialDataUpdatedAtVaut l'epoch par défaut : les données initiales sont périmées et refetchées au montage.
structuralSharingstructuralSharingActivé par défaut. Les données imbriquées inchangées gardent leur identité d'un fetch à l'autre.
notifyOnChangePropsNon disponibleToutes les transitions d'état émettent sur le stream.

Valeurs de retour

Champ TanStack QueryÉquivalent Qora
status: 'pending'state is Initial ou state is Loading(previousData: null)
status: 'error'state is Failure
status: 'success'state is Success
fetchStatus: 'fetching'fetchStatus == FetchStatus.fetching
fetchStatus: 'paused'fetchStatus == FetchStatus.paused
fetchStatus: 'idle'fetchStatus == FetchStatus.idle
isLoadingstate.isLoading
isFetchingfetchStatus == FetchStatus.fetching
isErrorstate.isError
isSuccessstate.isSuccess
isPendingstate is Initial || state is Loading(previousData: null)
datastate.dataOrNull ou Success(:final data) via correspondance de motifs
errorstate.errorOrNull ou Failure(:final error) via correspondance de motifs
dataUpdatedAtstate.updatedAt (extension, non-null uniquement sur Success)
errorUpdatedAtNon disponible comme champ séparé
isFetchedAfterMountNon disponible

Référence API : mutations

Options

Option TanStack QueryÉquivalent QoraNotes
mutationFnmutatorRenommé.
onMutateMutationOptions.onMutateMême rôle. La valeur de retour devient TContext.
onSuccessMutationOptions.onSuccessMême rôle. Signature : (TData, TVariables, TContext?).
onErrorMutationOptions.onErrorMême rôle. Signature : (Object, TVariables, TContext?).
onSettledMutationOptions.onSettledMême rôle. Signature : (TData?, Object?, TVariables, TContext?).
retryMutationOptions.retryCountRenommé. Valeur par défaut 0 (pas de retry).
retryDelayMutationOptions.retryDelayBackoff exponentiel.
networkModeMutationOptions.networkModeMêmes valeurs. Ajouter offlineQueue: true pour mettre en file les écritures faites hors-ligne et les rejouer à la reconnexion.
variablesParamètre de type TVariablesMême concept.
context (snapshot de rollback)Paramètre de type TContextMême concept. Retourné par onMutate, transmis à onError/onSettled.

Valeurs de retour / state

Champ TanStack QueryÉquivalent Qora
status: 'idle'state is MutationIdle
status: 'pending'state is MutationPending
status: 'error'state is MutationFailure
status: 'success'state is MutationSuccess
isIdlestate.isIdle
isPendingstate.isPending
isErrorstate.isError
isSuccessstate.isSuccess
datastate.dataOrNull
errorstate.errorOrNull
variablesstate.variablesOrNull
mutate(variables)mutate(variables): fire-and-forget, erreurs capturées dans le state
mutateAsync(variables)mutateAsync(variables): awaitable, erreurs propagées
reset()reset(): transitions vers MutationIdle

Référence API : QueryClient vers QoraClient

Méthode TanStack QueryÉquivalent Qora
invalidateQueries({ queryKey })client.invalidate(key)
invalidateQueries(filter)client.invalidateWhere(predicate) ou client.invalidateQueries(filter)
setQueryData(queryKey, updater)client.setQueryData<T>(key, data)
getQueryData(queryKey)client.getQueryData<T>(key): retourne T?
getQueryState(queryKey)client.getQueryState<T>(key): retourne QoraState<T>
prefetchQueryclient.prefetch<T>(key, fetcher, options)
resetQueriesclient.removeQuery(key) ou client.clear()
cancelQueriesNon disponible dans Qora v1
isFetching(queryKey)client.isFetchingCount (compteur global)
setDefaultOptionsQoraClientConfig.defaultOptions (défini à la construction)
getDefaultOptionsclient.config.defaultOptions
mount / unmountGéré par QoraScope / cycle de vie des widgets
clear()client.clear()

Différences clés

Les classes scellées remplacent les chaînes de statut

TanStack Query retourne des objets simples avec des champs status sous forme de chaîne et des raccourcis booléens (isLoading, isError, etc.). Qora retourne une classe scellée QoraState<T>. La correspondance de motifs exhaustive de Dart 3 est appliquée à la compilation, éliminant les branches d'état non gérées :

user_screen.dart
// TanStack Query (React)
if (isLoading) return <Spinner />;
if (isError) return <Error error={error} />;
return <UserCard user={data} />;

// Qora (Dart 3)
return switch (state) {
  Initial() || Loading(previousData: null) => const CircularProgressIndicator(),
  Failure(:final error, previousData: null) => ErrorScreen(error),
  _ => UserCard(state.dataOrNull!),
};

Le bras _ couvre Success, Loading(previousData != null) et Failure(previousData != null) : tous les cas où les données sont disponibles.


previousData est toujours présent

TanStack Query v5 conserve les données précédentes avec placeholderData: keepPreviousData. Dans Qora, Loading<T> et Failure<T> portent toujours previousData: T? : les données périmées restent accessibles pendant les rafraîchissements en arrière-plan et après une erreur, sans aucune option.

user_screen.dart
// Afficher les données périmées avec un indicateur pendant un rafraîchissement
case Loading(:final previousData) when previousData != null:
  return Stack(children: [
    UserCard(previousData),
    const LinearProgressIndicator(minHeight: 2),
  ]);

Si vous préférez que l'entrée reste en Success pendant le refetch, par exemple pour garder un tableau paginé stable, utilisez keepPreviousData: true.


select filtre les rebuilds, il ne transforme pas

Dans TanStack Query, select transforme les données renvoyées au composant. Dans Qora, select sur QoraBuilder et useQuery décide quand le widget se reconstruit : uniquement quand le type d'état ou la valeur sélectionnée change. L'état reçu est toujours l'état complet.

Pour transformer les données, Qora propose deux outils :

main.dart
// TanStack Query
useQuery({ queryKey, queryFn, select: (data) => data.name });

// Qora : transformer une fois, dans le cache (tous les abonnés voient le résultat)
QoraOptions(transform: (raw) => User.fromJson(raw as Map<String, dynamic>));

// Qora : transformer par consommateur, sur l'état
final nameState = userState.map((user) => user.name);
// QoraState<User> → QoraState<String>, previousData compris

// Qora : reconstruire uniquement quand le nom change
QoraBuilder<User>(
  queryKey: ['users', id],
  fetcher: () => api.getUser(id),
  select: (user) => user.name,
  builder: (context, state, _) => Text(state.dataOrNull?.name ?? ''),
);

gcTime remplace cacheTime

Qora utilise le nom de TanStack Query v5. gcTime est la durée pendant laquelle une entrée inactive reste en mémoire après l'annulation de son dernier abonné.


API Widget vs API Hook

L'API principale de React Query est basée sur les hooks (useQuery, useMutation). Qora fournit les deux :

  • QoraBuilder<T> et QoraMutationBuilder fonctionnent dans tout StatelessWidget ou StatefulWidget.
  • useQuery<T> et useMutation nécessitent HookWidget de flutter_hooks.

Les deux partagent le même cache QoraClient. Si un QoraBuilder a déjà récupéré ['users', id], useQuery l'obtient au premier frame depuis la même entrée.


QoraScope est un StatefulWidget, pas un Provider

TanStack Query utilise QueryClientProvider (contexte React). Qora utilise QoraScope, un StatefulWidget qui expose le client à son sous-arbre via un InheritedWidget interne. Accéder au client depuis n'importe quel descendant via context.qora ou QoraScope.of(context).


La persistance nécessite un enregistrement explicite des sérialiseurs

Les plugins de persistance de TanStack Query (ex. createSyncStoragePersister) utilisent JSON.stringify / JSON.parse sur le cache de requêtes complet. Qora nécessite un enregistrement explicite des sérialiseurs par type car Dart n'a pas de réflexion à l'exécution :

main.dart
// Requis avant hydrate()
client.registerSerializer<User>(
  QoraSerializer(toJson: (u) => u.toJson(), fromJson: User.fromJson),
  name: 'User',
);
await client.hydrate();

La chaîne name doit être stable entre les versions de l'application et les modes de build (y compris les builds obfusqués).


Pas d'équivalent React Suspense

TanStack Query supporte suspense: true pour s'intégrer avec React Suspense. Flutter n'a pas de mécanisme équivalent. Tout état asynchrone est géré via la correspondance de motifs sur QoraState<T> dans l'arbre de widgets.


Requêtes infinies

TanStack QueryQora
useInfiniteQueryInfiniteQueryBuilder / useInfiniteQuery
queryFn({ pageParam })fetcher(TPageParam pageParam)
initialPageParamInfiniteQueryOptions.initialPageParam
getNextPageParam(lastPage, pages)InfiniteQueryOptions.getNextPageParam(lastPage, pages)
getPreviousPageParamInfiniteQueryOptions.getPreviousPageParam
maxPagesInfiniteQueryOptions.maxPages
fetchNextPage()observer.fetchNextPage()
fetchPreviousPage()observer.fetchPreviousPage()
hasNextPageInfiniteSuccess.hasNextPage
hasPreviousPageInfiniteSuccess.hasPreviousPage
isFetchingNextPageInfiniteSuccess.isFetchingNextPage
isFetchingPreviousPageInfiniteSuccess.isFetchingPreviousPage
data.pagesInfiniteData.pages
data.pageParamsInfiniteData.pageParams
data.pages.flat()InfiniteData.flatten((page) => page.items)
queryClient.setQueryData (infini)client.setInfiniteQueryData<TData, TPageParam>(key, InfiniteData)
queryClient.getQueryData (infini)client.getInfiniteQueryData<TData, TPageParam>(key)

DevTools

Les DevTools de TanStack Query sont un panneau navigateur installé comme composant React. L'équivalent dans Qora est un overlay intégré à l'application : installez qora_devtools_overlay et enveloppez l'application avec QoraInspector. Il montre les requêtes, les mutations et une timeline, et n'affiche rien en build release.

Voir Vue d'ensemble des DevTools pour les instructions de configuration.


Liens connexes

Copyright © 2026