Requête infinie
InfiniteData<TData, TPageParam>
Conteneur immuable contenant toutes les pages récupérées et leurs paramètres de page correspondants.
TData est le type d'une seule page (ex. List<Post>). TPageParam est le type du paramètre de page (ex. int, String?).
pages et pageParams ont toujours la même longueur : pages[i] a été récupéré en utilisant pageParams[i].
Constructeur
const InfiniteData({
required List<TData> pages,
required List<TPageParam> pageParams,
})
Vérifie que pages.length == pageParams.length.
Propriétés
| Propriété | Type | Description |
|---|---|---|
pages | List<TData> | Toutes les pages récupérées dans l'ordre : première page à l'index 0. |
pageParams | List<TPageParam> | Paramètres utilisés pour récupérer chaque page (pageParams[i] → pages[i]). |
pageCount | int | Nombre total de pages actuellement chargées. |
isEmpty | bool | true quand aucune page n'a été chargée. |
isNotEmpty | bool | true quand au moins une page a été chargée. |
Méthodes
flatten
List<TItem> flatten<TItem>(Iterable<TItem> Function(TData page) selector)
Aplatit toutes les pages en une seule liste : la façon canonique de convertir les données paginées pour ListView.builder.
// TData == List<Post>
final posts = data.flatten((page) => page);
// TData est un objet de réponse avec une liste imbriquée
final posts = data.flatten((page) => page.items);
append
InfiniteData<TData, TPageParam> append(TData page, TPageParam param)
Retourne un nouvel InfiniteData avec page et param ajoutés à la fin. Utilisé en interne par fetchNextPage.
prepend
InfiniteData<TData, TPageParam> prepend(TData page, TPageParam param)
Retourne un nouvel InfiniteData avec page et param ajoutés au début. Utilisé en interne par fetchPreviousPage.
dropFirst
InfiniteData<TData, TPageParam> dropFirst()
Retourne un nouvel InfiniteData sans sa première page. Appelé lors du paging fenêtré quand maxPages est dépassé après un fetchNextPage.
dropLast
InfiniteData<TData, TPageParam> dropLast()
Retourne un nouvel InfiniteData sans sa dernière page. Appelé lors du paging fenêtré quand maxPages est dépassé après un fetchPreviousPage.
InfiniteQueryState<TData, TPageParam>
Machine à états de classe sealed pour une requête infinie. Pattern matching exhaustif avec switch :
switch (state) {
case InfiniteInitial() || InfiniteLoading():
return const CircularProgressIndicator();
case InfiniteSuccess(:final data, :final hasNextPage, :final isFetchingNextPage):
return PostFeed(
items: data.flatten((page) => page),
hasMore: hasNextPage,
loadingMore: isFetchingNextPage,
);
case InfiniteFailure(:final error, :final previousData):
if (previousData != null) {
return Column(children: [
PostFeed(items: previousData.flatten((p) => p)),
ErrorBanner(error),
]);
}
return ErrorScreen(error);
}
InfiniteInitial
final class InfiniteInitial<TData, TPageParam> extends InfiniteQueryState<TData, TPageParam>
La requête n'a pas encore été exécutée. État par défaut quand aucun fetch n'a été déclenché.
InfiniteLoading
final class InfiniteLoading<TData, TPageParam> extends InfiniteQueryState<TData, TPageParam>
Le fetch de la première page est en cours. Aucune page n'a encore été chargée.
Après le chargement de la première page, l'état ne revient jamais à InfiniteLoading. Les fetches de pages suivantes signalent leur progression via isFetchingNextPage/isFetchingPreviousPage sur InfiniteSuccess, gardant les pages existantes visibles.
InfiniteSuccess
final class InfiniteSuccess<TData, TPageParam> extends InfiniteQueryState<TData, TPageParam>
Toutes les pages actuellement chargées, avec les indicateurs de statut de pagination.
Propriétés
| Propriété | Type | Description |
|---|---|---|
data | InfiniteData<TData, TPageParam> | Toutes les pages chargées et leurs paramètres de page. |
hasNextPage | bool | true quand getNextPageParam retourne non-null pour la dernière page. |
hasPreviousPage | bool | true quand getPreviousPageParam retourne non-null pour la première page. Toujours false si pas de getPreviousPageParam. |
updatedAt | DateTime | Quand cet état a été mis à jour avec succès pour la dernière fois. |
isFetchingNextPage | bool | true pendant un fetch de page suivante. Afficher un indicateur de chargement en bas ; data reste valide. |
isFetchingPreviousPage | bool | true pendant un fetch de page précédente. Afficher un indicateur de chargement en haut ; data reste valide. |
copyWith
InfiniteSuccess<TData, TPageParam> copyWith({
InfiniteData<TData, TPageParam>? data,
bool? isFetchingNextPage,
bool? isFetchingPreviousPage,
bool? hasNextPage,
bool? hasPreviousPage,
DateTime? updatedAt,
})
Retourne une copie avec les champs spécifiés remplacés. Les champs non spécifiés conservent leurs valeurs actuelles.
InfiniteFailure
final class InfiniteFailure<TData, TPageParam> extends InfiniteQueryState<TData, TPageParam>
Un échec de fetch, avec previousData optionnel pour la dégradation gracieuse.
Propriétés
| Propriété | Type | Description |
|---|---|---|
error | Object | L'erreur levée par la fonction de fetch (après tous les retries). |
stackTrace | StackTrace? | Stack trace optionnelle. |
previousData | InfiniteData<TData, TPageParam>? | Dernières pages chargées avec succès, le cas échéant. Non-null quand l'échec survient après le chargement de pages. |
Quand previousData est non-null, afficher le contenu existant à côté d'un indicateur d'erreur plutôt que de remplacer toute la vue.
InfiniteQueryOptions<TData, TPageParam>
Configuration pour une requête infinie. Combine les QoraOptions standard avec des paramètres spécifiques à la pagination.
Constructeur
const InfiniteQueryOptions({
required TPageParam initialPageParam,
required TPageParam? Function(TData lastPage, List<TData> allPages) getNextPageParam,
TPageParam? Function(TData firstPage, List<TData> allPages)? getPreviousPageParam,
int? maxPages,
QoraOptions baseOptions = const QoraOptions(),
})
Vérifie maxPages == null || maxPages >= 1.
Propriétés
| Propriété | Type | Requis | Description |
|---|---|---|---|
initialPageParam | TPageParam | Oui | Paramètre pour la toute première page (ex. 1, 0, null ou ''). |
getNextPageParam | TPageParam? Function(TData lastPage, List<TData> allPages) | Oui | Retourne le paramètre de la prochaine page, ou null quand il n'y a plus de pages (définit hasNextPage à false). |
getPreviousPageParam | TPageParam? Function(TData firstPage, List<TData> allPages)? | Non | Retourne le paramètre de la page précédente. Nécessaire uniquement pour le scroll bidirectionnel. Quand null, hasPreviousPage est toujours false. |
maxPages | int? | Non | Pages maximum gardées en mémoire. Quand dépassé, la page la plus ancienne est supprimée à fetchNextPage (ou la plus récente à fetchPreviousPage). Doit être >= 1. |
baseOptions | QoraOptions | Non | Options standard de retry, stale time, cache time et network mode appliquées à chaque fetch de page. Fusionnées par-dessus QoraClientConfig.defaultOptions. |
InfiniteQueryObserver<TData, TPageParam>
Le moteur de pagination central. Gère le cycle de vie complet d'une seule requête infinie : récupération des pages, émission des transitions d'état et respect des gardes de concurrence.
Typiquement créé dans State.initState d'un widget Flutter et disposé dans State.dispose. Pour un binding Flutter prêt à l'emploi, utiliser InfiniteQueryBuilder à la place.
Plusieurs observateurs partageant la même key sur le même client partagent la même entrée de cache sous-jacente, de sorte que tous les listeners reçoivent les mêmes transitions d'état en synchronie.
Constructeur
InfiniteQueryObserver({
required QoraClient client,
required Object key,
required InfiniteQueryFunction<TData, TPageParam> fetcher,
required InfiniteQueryOptions<TData, TPageParam> options,
})
Propriétés
| Propriété | Type | Description |
|---|---|---|
stream | Stream<InfiniteQueryState<TData, TPageParam>> | Émet l'état actuel immédiatement, puis toutes les futures transitions. |
state | InfiniteQueryState<TData, TPageParam> | Snapshot synchrone de l'état actuel. |
Méthodes
fetch
Future<void> fetch()
Récupère la première page. Sans effet quand :
- Des données sont déjà chargées (l'état n'est pas
InfiniteInitial). - Un fetch initial est déjà en cours.
Transitions : InfiniteInitial → InfiniteLoading → InfiniteSuccess | InfiniteFailure.
fetchNextPage
Future<void> fetchNextPage()
Récupère la page suivante et l'ajoute. Sans effet quand :
- Aucune donnée n'a encore été chargée (appeler
fetchd'abord). hasNextPageestfalse.- Un fetch de page suivante ou précédente est déjà en cours.
Pendant le fetch, définit isFetchingNextPage: true sur l'InfiniteSuccess actuel : les pages existantes restent visibles. En cas d'échec, transite vers InfiniteFailure avec previousData renseigné.
fetchPreviousPage
Future<void> fetchPreviousPage()
Récupère la page précédente et la prépend. Sans effet quand :
getPreviousPageParamn'est pas configuré.hasPreviousPageestfalse.- Un fetch est déjà en cours.
Pendant le fetch, définit isFetchingPreviousPage: true. En cas d'échec, transite vers InfiniteFailure avec previousData.
refetch
Future<void> refetch()
Re-récupère toutes les pages actuellement chargées en séquence, en préservant le nombre de pages. Utilise les pageParams originaux stockés dans InfiniteData. Utile après client.invalidateInfiniteQuery(key) ou un pull-to-refresh.
- Si aucune donnée n'est chargée, délègue à
fetch(). - Signale la progression via
isFetchingNextPage: truesur l'InfiniteSuccessactuel. - En cas d'échec, transite vers
InfiniteFailureavecpreviousData.
dispose
void dispose()
Libère cet observateur. Après le dispose, tous les appels de méthodes ultérieurs sont ignorés silencieusement. L'entrée de cache sous-jacente n'est pas supprimée : les autres observateurs partageant la même clé continuent de fonctionner normalement.
Garanties de concurrence
Tous les gardes (_isFetchingInitial, _isFetchingNext, _isFetchingPrevious, _isRefetching) sont définis comme première instruction synchrone dans leur méthode : avant tout await. Cela prévient les conditions de course dues aux événements de scroll rapide ou aux interactions UI même avant le premier aller-retour réseau.
InfiniteQueryBuilder<TData, TPageParam>
Widget Flutter qui lie une requête infinie à l'arbre de widgets. Voir le guide InfiniteQueryBuilder pour des exemples d'utilisation.
Constructeur
const InfiniteQueryBuilder({
Key? key,
required Object queryKey,
required InfiniteQueryFunction<TData, TPageParam> fetcher,
required InfiniteQueryOptions<TData, TPageParam> options,
required Widget Function(
BuildContext context,
InfiniteQueryState<TData, TPageParam> state,
InfiniteQueryController<TData, TPageParam> controller,
) builder,
QoraClient? client,
bool enabled = true,
})
Props
| Prop | Type | Défaut | Description |
|---|---|---|---|
queryKey | Object (List ou QoraKey) | requis | Clé de cache. La changer dispose l'observateur actuel et repart de initialPageParam. |
fetcher | InfiniteQueryFunction<TData, TPageParam> | requis | Future<TData> Function(TPageParam pageParam) : récupère une seule page. |
options | InfiniteQueryOptions<TData, TPageParam> | requis | Configuration de pagination. |
builder | Widget Function(BuildContext, InfiniteQueryState, InfiniteQueryController) | requis | Construit l'arbre de widgets depuis l'état et le contrôleur. |
client | QoraClient? | null | Remplace le QoraClient depuis QoraScope. Utile pour les tests. |
enabled | bool | true | Quand false, le fetch de la première page est supprimé. Le widget observe toujours l'état en cache actuel. |
InfiniteQueryController<TData, TPageParam>
Interface stable exposant les actions de pagination au callback InfiniteQueryBuilder.builder. La référence du contrôleur est stable tant que queryKey et client restent inchangés.
Méthodes
| Méthode | Signature | Description |
|---|---|---|
fetchNextPage() | Future<void> | Récupère et ajoute la page suivante. Sans effet si hasNextPage est false ou un fetch est en cours. |
fetchPreviousPage() | Future<void> | Récupère et prépend la page précédente. Nécessite getPreviousPageParam configuré. |
refetch() | Future<void> | Re-récupère toutes les pages chargées en séquence. Utile pour le pull-to-refresh (onRefresh: controller.refetch). |
InfiniteQueryFunction<TData, TPageParam>
typedef InfiniteQueryFunction<TData, TPageParam> = Future<TData> Function(
TPageParam pageParam,
);
Le type du paramètre fetcher sur InfiniteQueryObserver et InfiniteQueryBuilder. Reçoit le paramètre de page calculé par getNextPageParam/getPreviousPageParam et retourne un Future résolvant en une seule page de données.
QoraClient : Méthodes de requête infinie
watchInfiniteState
Stream<InfiniteQueryState<TData, TPageParam>> watchInfiniteState<TData, TPageParam>(Object key)
Retourne un stream broadcast qui émet immédiatement l'InfiniteQueryState actuel pour key, puis émet toutes les futures transitions. S'abonner empêche le GC de l'entrée de cache.
getInfiniteQueryState
InfiniteQueryState<TData, TPageParam> getInfiniteQueryState<TData, TPageParam>(Object key)
Snapshot synchrone de l'état actuel. Retourne InfiniteInitial() si aucune entrée n'existe en cache.
getInfiniteQueryData
InfiniteData<TData, TPageParam>? getInfiniteQueryData<TData, TPageParam>(Object key)
Retourne l'InfiniteData de l'état InfiniteSuccess actuel, ou null si l'état n'est pas InfiniteSuccess.
final snapshot = client.getInfiniteQueryData<List<Post>, int>(['posts']);
setInfiniteQueryData
void setInfiniteQueryData<TData, TPageParam>(
Object key,
InfiniteData<TData, TPageParam> data, {
bool? hasNextPage,
bool? hasPreviousPage,
})
Injecte directement InfiniteData dans le cache, poussant un état InfiniteSuccess vers tous les abonnés actifs. Utiliser pour les mises à jour optimistes.
// Prépendre optimistement un nouveau post à la page 1
final snapshot = client.getInfiniteQueryData<List<Post>, int>(['posts']);
if (snapshot != null) {
client.setInfiniteQueryData(
['posts'],
InfiniteData(
pages: [
[Post.optimistic(title), ...snapshot.pages.first],
...snapshot.pages.skip(1),
],
pageParams: snapshot.pageParams,
),
);
}
try {
await api.createPost(title);
client.invalidateInfiniteQuery(['posts']);
} catch (_) {
if (snapshot != null) client.setInfiniteQueryData(['posts'], snapshot);
}
updateInfiniteQueryState
void updateInfiniteQueryState<TData, TPageParam>(
Object key,
InfiniteQueryState<TData, TPageParam> state,
)
Le chemin d'écriture brut pour n'importe quel InfiniteQueryState. Utilisé en interne par InfiniteQueryObserver. Préférer setInfiniteQueryData pour les mises à jour uniquement des données.
invalidateInfiniteQuery
void invalidateInfiniteQuery(Object key)
Réinitialise l'entrée de cache pour key à InfiniteInitial. Les instances InfiniteQueryBuilder actives détectent la réinitialisation et re-récupèrent automatiquement la première page, de sorte que l'UI ne reste jamais vide.
await api.createPost(title);
client.invalidateInfiniteQuery(['posts']);
Voir aussi
- Guide des requêtes infinies : machine à états, stratégies de pagination, scroll bidirectionnel, paging fenêtré
- InfiniteQueryBuilder : référence du widget Flutter avec patterns et exemples
- API QoraClient : référence complète du client pour les requêtes standard (non paginées)
- QoraOptions : retry, stale time, cache time et network mode
PersistQoraClient
Sous-classe de QoraClient qui persiste les résultats des requêtes dans un StorageAdapter et les restaure au démarrage via hydrate().
Vue d'ensemble
Voir chaque requête, mutation et entrée de cache de l'application en cours d'exécution, et agir dessus, depuis un panneau intégré à l'application.