Référence de l'API

QoraState

Hiérarchie de classes sealed représentant les quatre états possibles d'une requête. Le pattern matching exhaustif est imposé à la compilation.

Hiérarchie de classes

lib/src/state/qora_state.dart
sealed class QoraState<T> { ... }

final class Initial<T>  extends QoraState<T> { ... }
final class Loading<T>  extends QoraState<T> { ... }
final class Success<T>  extends QoraState<T> { ... }
final class Failure<T>  extends QoraState<T> { ... }

QoraState<T> : Base

Propriétés (disponibles sur tous les états)

PropriétéTypeDescription
hasDatabooltrue pour Success, ou Loading/Failure avec des données précédentes
dataOrNullT?Meilleures données disponibles dans tous les états, ou null
isInitialbooltrue si Initial
isLoadingbooltrue si Loading
isSuccessbooltrue si Success
isErrorbooltrue si Failure
errorOrNullObject?Erreur de Failure, ou null

map<R>(R Function(T) transform)

Transforme le type de données tout en préservant la structure d'état. previousData dans Loading/Failure est également transformé.

main.dart
final nameState = userState.map((user) => user.name);
// Success<User> → Success<String>

when({onInitial, onLoading, onSuccess, onError})

Exécute des callbacks pour l'état actuel. Les quatre callbacks sont optionnels.

main.dart
state.when(
  onSuccess: (data, updatedAt) => print('Chargé : ${data.name}'),
  onError: (error, stackTrace, previousData) => showSnackBar('$error'),
);

maybeWhen<R>({required orElse, onInitial, onLoading, onSuccess, onError})

Mappe l'état vers une valeur de type R. Les états non gérés tombent dans orElse.

main.dart
final widget = state.maybeWhen(
  onSuccess: (data, _) => UserCard(data),
  orElse: () => const CircularProgressIndicator(),
);

Initial<T>

La requête n'a pas encore été exécutée. État par défaut pour toute clé qui n'a jamais été chargée ou a été supprimée du cache.

main.dart
const Initial<User>()

state.isInitial   // true
state.hasData     // false
state.dataOrNull  // null

Loading<T>

Un fetch est activement en cours.

Champs

ChampTypeDescription
previousDataT?Dernières données réussies (null lors du premier fetch)
main.dart
Loading<User>()                          // premier fetch
Loading<User>(previousData: cachedUser)  // rechargement en arrière-plan

Propriétés (extensions)

PropriétéTypeDescription
isFirstLoadbooltrue quand previousData == null
isRefreshingbooltrue quand previousData != null
hasDatabooltrue quand previousData != null
user_page.dart
case Loading(:final previousData):
  return previousData != null
    ? Stack(children: [UserCard(previousData), const LinearProgressIndicator()])
    : const CircularProgressIndicator();

Success<T>

Les données ont été récupérées avec succès.

Champs

ChampTypeDescription
dataTLes données récupérées
updatedAtDateTimeHorodatage du dernier fetch réussi

Propriétés et méthodes

MembreTypeDescription
ageDurationTemps écoulé depuis updatedAt
isStale(Duration threshold)booltrue si age > threshold
successDataOrNull (ext.)T?Retourne data (null pour les autres états)
user_page.dart
case Success(:final data, :final updatedAt):
  return Column(children: [
    UserCard(data),
    Text('Mis à jour ${_timeAgo(updatedAt)}'),
  ]);

Factory

main.dart
Success.now(data)  // équivalent à Success(data: data, updatedAt: DateTime.now())

Failure<T>

Le fetch a échoué après toutes les tentatives de retry.

Champs

ChampTypeDescription
errorObjectL'erreur levée
stackTraceStackTrace?Stack trace optionnelle
previousDataT?Dernières données réussies (permet la dégradation gracieuse)
user_page.dart
case Failure(:final error, :final previousData):
  return Column(children: [
    if (previousData != null) ...[
      UserCard(previousData),   // afficher les données périmées
      const SizedBox(height: 8),
    ],
    ErrorBanner('$error'),
  ]);

Extensions sur QoraState<T>

Exportées depuis package:qora/qora.dart via state_extensions.dart.

Accès aux données

main.dart
state.requireData()        // T : lève StateError si pas de données
state.successDataOrNull    // T? : données uniquement depuis Success
state.updatedAt            // DateTime? : updatedAt depuis Success, null sinon
state.status               // enum QoraStatus (initial/loading/success/error)

Mapping

main.dart
state.mapData((data) => data.name)      // comme map : données Success et previousData
state.fold(
  onInitial: () => 'non chargé',
  onLoading: (prev) => 'chargement...',
  onSuccess: (data, _) => data.name,
  onError: (error, _, __) => 'erreur',
)

Combinaison

main.dart
// Deux états → un état combiné (Success uniquement quand les deux sont Success)
userState.combine(postsState, (user, posts) => UserWithPosts(user, posts))

// Listes et tuples
QoraStateUtils.combineList([s1, s2, s3])
QoraStateUtils.combine2(userState, settingsState)
QoraStateUtils.combine3(userState, postsState, tagsState)

Extensions sur Stream<QoraState<T>>

main.dart
stream.whereHasData()                   // uniquement les états avec des données
stream.whereSuccess()                   // uniquement les états Success
stream.whereError()                     // uniquement les états Failure
stream.dataOrNull()                     // Stream<T?> : null pour les états sans données
stream.data()                           // Stream<T> : ignore les états sans données
stream.mapData((data) => transform(data)) // Stream<QoraState<R>>
stream.delayLoading(Duration(milliseconds: 300))

Sérialisation : QoraStateCodec<T>

cache_storage.dart
final codec = QoraStateCodec<User>(
  encode: (user) => user.toJson(),
  decode: (json) => User.fromJson(json as Map<String, dynamic>),
);

// Encoder
final json = codec.encodeState(state); // Map<String, dynamic>

// Décoder
final restored = codec.decodeState(json); // QoraState<User>

Enum QoraStatus

Un enum de statut simplifié pour les cas où la classe sealed complète n'est pas nécessaire :

main.dart
state.status  // QoraStatus.initial | .loading | .success | .error

state.status.isLoading  // bool
state.status.isSuccess  // bool
state.status.isError    // bool
Copyright © 2026