FutureBuilder — définition, travailler avec Future dans Flutter

Auteur : IT Sectr Publié le : 2026-07-02 Temps de lecture : 8 min

FutureBuilder est un widget dans Flutter qui reconstruit automatiquement son interface en fonction de l’état actuel d’AsyncSnapshot obtenu à partir d’un Future fourni. Contrairement à l’appel manuel de setState après await, FutureBuilder offre une approche déclarative : il s’abonne au Future lors du premier rendu et appelle la fonction builder à chaque changement d’état — chargement, erreur ou données prêtes. Selon la Référence de l’API Flutter (2026), FutureBuilder est particulièrement utile pour charger des données depuis le réseau, lire dans une base de données et toutes les opérations asynchrones où l’interface doit afficher un indicateur de chargement, un message d’erreur ou un contenu prêt.

Points Clés

  • FutureBuilder — widget Flutter pour construire l’interface basée sur l’état du Future via AsyncSnapshot (none, waiting, active, done)
  • AsyncSnapshot — un objet contenant l’état actuel d’une opération asynchrone : connectionState, data et error
  • builder — une fonction de rappel invoquée à chaque changement d’état du Future pour reconstruire l’interface
  • Gestion des erreurs — AsyncSnapshot.hasError permet d’afficher une interface de secours en cas d’échec d’une opération asynchrone
  • ConnectionState — une énumération avec quatre valeurs : none (aucune opération), waiting (attente), active (flux), done (terminé)

Qu’est-ce que FutureBuilder dans Flutter

FutureBuilder est un widget intégré de Flutter du package widgets qui prend un Future et une fonction builder. Lorsque l’état du Future change (en cours d’exécution, terminé avec données, terminé avec erreur), FutureBuilder reconstruit automatiquement l’interface en appelant le builder avec un nouvel AsyncSnapshot. Cela élimine le besoin de gérer manuellement l’état de chargement via setState et des indicateurs.

Contrairement à StreamBuilder, qui fonctionne avec des flux de données (Stream), FutureBuilder est conçu pour des opérations asynchrones uniques : requête HTTP, lecture de fichier, requête de base de données. FutureBuilder gère lui-même l’abonnement au Future : lors de la première construction, il démarre le Future et suit son achèvement. Lorsque le widget est détruit, FutureBuilder n’annule pas le Future — c’est la responsabilité du développeur.

Selon le Flutter Cookbook (2026), FutureBuilder est recommandé pour les cas où une opération asynchrone s’exécute une fois lors de l’initialisation de l’écran. Pour les opérations récurrentes ou les flux de données, utilisez StreamBuilder. Les deux widgets suivent le même modèle d’interface réactive, mais FutureBuilder est optimisé pour les requêtes uniques.

Comment FutureBuilder fonctionne en interne

L’implémentation interne de FutureBuilder s’abonne au Future en utilisant Future.then et catchError. Au démarrage, FutureBuilder définit connectionState sur ConnectionState.waiting et appelle le builder avec des données vides. En cas de succès, connectionState passe à ConnectionState.done avec les données. En cas d’erreur, snapshot.error est rempli avec l’objet d’erreur. Chaque changement déclenche une reconstruction du widget.

AsyncSnapshot : états et propriétés

AsyncSnapshot est un objet conteneur que FutureBuilder passe à la fonction builder à chaque changement d’état. Il contient toutes les informations sur le statut actuel de l’opération asynchrone : si le chargement est en cours, quelles données ont été reçues ou si une erreur s’est produite. Comprendre AsyncSnapshot est la clé pour construire correctement l’interface avec FutureBuilder.

PropriétéTypeDescription
connectionStateConnectionStateÉtat actuel de la connexion (none, waiting, active, done)
dataT?Données reçues du Future (null jusqu’à la fin ou en cas d’erreur)
errorObject?Objet d’erreur si le Future s’est terminé avec une exception
hasDatabooltrue si data n’est pas null et connectionState est ConnectionState.done
hasErrorbooltrue si le Future s’est terminé avec une erreur

ConnectionState : quatre états d’une opération asynchrone

L’énumération ConnectionState définit l’étape d’une opération asynchrone. None — état initial lorsque le Future n’a pas encore été démarré (rarement utilisé, généralement lors de la première construction sans initialData). Waiting — le Future est en cours d’exécution, données pas encore reçues. Active — utilisé uniquement par StreamBuilder pour les flux avec données partielles. Done — le Future est terminé, les données sont disponibles via snapshot.data ou l’erreur via snapshot.error.

La gestion correcte de tous les états d’AsyncSnapshot dans la fonction builder est une exigence obligatoire pour le code de production. Si vous ne gérez pas l’état waiting, l’utilisateur verra un écran vide pendant le chargement. Si vous ne gérez pas hasError, l’utilisateur recevra une Exception sans explication. Le modèle recommandé : vérifier hasError → vérifier hasData → afficher le chargement par défaut.

Patrons d’utilisation de FutureBuilder

FutureBuilder peut être utilisé dans plusieurs modèles standards, chacun résolvant une tâche spécifique. Examinons les principaux scénarios : chargement des données à l’initialisation, chargement avec cache, requêtes parallèles et gestion des erreurs avec réessai.

Chargement des données à l’initialisation de l’écran

Le modèle le plus courant — FutureBuilder dans la méthode build d’un StatefulWidget ou StatelessWidget. Le Future est passé depuis initState ou créé directement dans build. Il est important de ne pas créer le Future dans la méthode build lors de chaque reconstruction — cela entraînerait des requêtes répétées. Utilisez un Future stocké dans un champ du State.

Chargement avec cache et actualisation

Pour éviter les requêtes répétées, FutureBuilder peut être combiné avec CachedNetworkImage ou un cache local. Après le premier chargement, les données sont sauvegardées en mémoire ou dans SharedPreferences, et FutureBuilder affiche instantanément les données en cache tout en les actualisant depuis le réseau en parallèle. Cela améliore l’expérience utilisateur grâce à une réponse instantanée.

Selon pub.dev (2026), la mise en cache est particulièrement pertinente pour les images et les listes de données. FutureBuilder avec CachedNetworkImageProvider affiche automatiquement une image en cache, et en son absence — un indicateur de chargement suivi du fichier téléchargé.

FutureBuilder vs setState : que choisir

FutureBuilder et la gestion manuelle de l’état via setState sont deux approches pour l’interface asynchrone dans Flutter. Chacune a ses avantages et ses limites. Le choix dépend de la complexité de l’écran et du nombre d’opérations asynchrones.

FutureBuilder gagne en simplicité : vous n’avez pas besoin de déclarer des champs pour l’état de chargement, les données et l’erreur — tout est géré via AsyncSnapshot. Il est idéal pour les écrans simples avec une opération asynchrone (une requête HTTP, une lecture de base de données). Cependant, avec 5+ opérations asynchrones sur un seul écran, FutureBuilder crée un embranchement excessif — aboutissant à une « pyramide » de FutureBuilders imbriqués.

setState avec des indicateurs d’état manuels offre plus de contrôle et de lisibilité pour une logique complexe. Pour les écrans avec plusieurs requêtes dépendantes (charger l’utilisateur → charger ses commandes → charger les détails de la commande), il est préférable d’utiliser setState avec ChangeNotifier ou Bloc. Selon le Guide de Gestion d’État Flutter (2026), pour les scénarios complexes, Riverpod ou Bloc sont recommandés plutôt que FutureBuilder, car ils offrent une meilleure séparation de la logique et de la présentation.

Exemple FutureBuilder avec chargement de données réseau

Considérons un exemple pratique de FutureBuilder pour charger une liste d’utilisateurs depuis une API REST. Le code démontre le traitement correct des trois états d’AsyncSnapshot : chargement, erreur et données prêtes.

dart
class UserListPage extends StatefulWidget {
  const UserListPage({super.key});

  @override
  State<UserListPage> createState() => _UserListPageState();
}

class _UserListPageState extends State<UserListPage> {
  final Future<List<User>> usersFuture = UserRepository().fetchUsers();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Utilisateurs')),
      body: FutureBuilder<List<User>>(
        future: usersFuture,
        builder: (context, AsyncSnapshot<List<User>> snapshot) {
          if (snapshot.hasError) {
            return Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  const Icon(Icons.error_outline, size: 48, color: Colors.red),
                  const SizedBox(height: 16),
                  Text('Erreur : ${snapshot.error}'),
                ],
              ),
            );
          }

          if (snapshot.hasData) {
            final users = snapshot.data!;
            return ListView.builder(
              itemCount: users.length,
              itemBuilder: (context, index) {
                return ListTile(
                  leading: CircleAvatar(backgroundImage: NetworkImage(users[index].avatarUrl)),
                  title: Text(users[index].name),
                  subtitle: Text(users[index].email),
                );
              },
            );
          }

          return const Center(child: CircularProgressIndicator());
        },
      ),
    );
  }
}

Dans l’exemple, FutureBuilder gère les trois états. En cas d’erreur, une icône avec un message d’erreur est affichée. En cas de chargement réussi — une ListView avec des avatars et des noms. Pendant le chargement — un CircularProgressIndicator. Le Future est déclaré comme un champ de classe, ce qui empêche les appels répétés lors des reconstructions. Ce modèle couvre 90% des scénarios d’utilisation de FutureBuilder dans les applications mobiles.

Foire Aux Questions

Pourquoi FutureBuilder appelle-t-il le builder plusieurs fois ?

FutureBuilder appelle le builder à chaque changement d’état du Future : la première fois à la création (connectionState : none ou waiting), la deuxième fois à la fin (connectionState : done). Si le widget parent est reconstruit, FutureBuilder est également reconstruit. Pour éviter des appels répétés, assurez-vous que le Future est créé en dehors de la méthode build — sinon chaque appel de build créera un nouveau Future.

Comment éviter une requête répétée lors de la reconstruction ?

Stockez le Future dans un champ de StatefulWidget (dans initState) ou utilisez la mémoïsation. Si le Future est créé à l’intérieur de la méthode build, chaque appel de build créera un nouveau Future, et FutureBuilder redémarrera l’opération asynchrone. Pour StatelessWidget, utilisez le paquet cached_future ou des widgets keep-alive pour que le Future s’exécute une seule fois indépendamment des reconstructions.

En quoi FutureBuilder diffère-t-il de StreamBuilder ?

FutureBuilder est conçu pour des opérations asynchrones uniques (une requête HTTP, une lecture de base de données). StreamBuilder fonctionne avec des flux de données pouvant émettre plusieurs valeurs dans le temps (chat, mises à jour de prix, géolocalisation). StreamBuilder supporte ConnectionState.active pour les données partielles, tandis que FutureBuilder ne supporte que waiting et done.

Comment utiliser FutureBuilder avec plusieurs Futures ?

Pour plusieurs Futures parallèles, utilisez Future.wait et passez le résultat à un seul FutureBuilder. Future.wait prend une liste de Futures et retourne un Future — lorsque tous les Futures sont terminés, le builder reçoit un tableau de résultats. Pour les requêtes séquentielles, utilisez une chaîne Future.then dans un seul Future ou des FutureBuilders imbriqués (moins lisible). Une alternative est le paquet riverpod avec AsyncValue pour plusieurs états asynchrones.

Comment annuler un Future en quittant l’écran ?

FutureBuilder n’annule pas le Future automatiquement. Pour annuler, utilisez CancelableOperation du paquet async ou un mécanisme personnalisé via un indicateur cancelled dans State. Définissez l’indicateur dans dispose(), et vérifiez-le après la fin du Future avant d’appeler setState. Alternativement, utilisez le paquet riverpod avec AutoDispose, qui annule automatiquement les opérations asynchrones en quittant l’écran.

Résumé

  • FutureBuilder — widget Flutter pour la construction déclarative d’interface basée sur l’état du Future via AsyncSnapshot (waiting, done, error)
  • AsyncSnapshot — conteneur avec connectionState, data et error ; essentiel pour le traitement correct de tous les états d’opération asynchrone
  • builder — rappel avec trois branches : hasError (afficher l’erreur), hasData (afficher les données), default (indicateur de chargement)
  • FutureBuilder vs setState — FutureBuilder est plus simple pour une opération, setState avec Bloc/Riverpod est meilleur pour la logique complexe avec plusieurs requêtes
  • Prévention des requêtes répétées — le Future doit être un champ du State, ne le créez pas dans la méthode build pour éviter les redémarrages à chaque reconstruction
  • Annulation du Future — FutureBuilder n’annule pas le Future lors du dispose ; utilisez CancelableOperation ou un indicateur d’annulation pour empêcher setState après la destruction
  • Plusieurs Futures — pour les requêtes parallèles, utilisez Future.wait avec un seul FutureBuilder ; pour les séquentielles — des chaînes dans un seul Future

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi