InheritedWidget — ce que c'est, transmission de données dans l'arbre et fonctionnement

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

InheritedWidget est un widget spécial dans Flutter qui transmet les données vers le bas dans l'arbre de widgets sans les passer explicitement via les constructeurs. Les widgets enfants accèdent aux données via BuildContext et s'abonnent automatiquement aux mises à jour. Lorsque les données dans InheritedWidget changent, tous les widgets dépendants se reconstruisent. Selon Flutter API Reference, 2025, InheritedWidget est à la base de Theme, MediaQuery, Localizations et de la plupart des bibliothèques de gestion d'état.

Points clés

  • InheritedWidget transmet les données vers le bas dans l'arbre Widget Tree sans les passer explicitement à travers chaque widget.
  • Abonnement automatique — les widgets utilisant dependOnInheritedWidgetOfExactType se reconstruisent lorsque les données changent.
  • Theme et MediaQuery sont des exemples intégrés d'InheritedWidget, disponibles dans chaque application Flutter.
  • Provider et Riverpod sont construits sur InheritedWidget et étendent ses capacités pour la gestion d'état.
  • Implémentation correcte nécessite de redéfinir updateShouldNotify pour éviter les reconstructions inutiles.

Qu'est-ce qu'InheritedWidget dans Flutter?

InheritedWidget est un widget qui rend ses données disponibles pour tous les descendants dans l'arbre Widget Tree. Contrairement à un widget ordinaire qui ne transmet les données qu'via les constructeurs aux éléments enfants, InheritedWidget permet à n'importe quel widget dans le sous-arbre d'accéder aux données sans chaîne de paramètres. Cela résout le problème de « prop drilling » — la transmission de données à travers de nombreux widgets intermédiaires qui n'utilisent pas ces données eux-mêmes.

InheritedWidget intégrés

Flutter inclut plusieurs InheritedWidget intégrés : Theme (schéma de couleurs et styles), MediaQuery (taille d'écran, orientation, densité de pixels), Localizations (chaînes localisées), Directionality (direction du texte), DefaultTextStyle (style de texte par défaut). Ces widgets sont définis par des widgets racines comme MaterialApp et sont disponibles dans toute l'application.

Cycle de vie d'InheritedWidget

InheritedWidget n'a pas d'état propre — il stocke les données transmises via le constructeur. Lorsque le parent d'InheritedWidget est reconstruit avec de nouvelles données, la méthode updateShouldNotify est appelée pour comparer les anciennes et nouvelles données. Si la méthode retourne true, tous les widgets dépendants sont marqués pour reconstruction. C'est un mécanisme de mise à jour réactive simple mais efficace.

Comment fonctionne la transmission de données via InheritedWidget

Le mécanisme de transmission de données via InheritedWidget est basé sur l'Element Tree. Lorsqu'un widget appelle dependOnInheritedWidgetOfExactType, l'élément correspondant enregistre une dépendance sur InheritedElement. Lorsque InheritedWidget change, InheritedElement notifie tous les éléments dépendants, qui se reconstruisent dans l'image suivante.

Enregistrement de dépendance

La méthode dependOnInheritedWidgetOfExactType ne trouve pas seulement InheritedWidget dans l'arbre — elle abonne l'élément actuel aux notifications. Si vous utilisiez findAncestorWidgetOfExactType au lieu de dependOn, le widget obtiendrait les données mais ne se reconstruirait pas lorsqu'elles changent. C'est une différence importante : dependOn est un abonnement, findAncestor est une recherche unique.

Parcours de l'arbre d'InheritedWidget

Lorsqu'un widget demande un InheritedWidget, Flutter remonte l'Element Tree de l'élément actuel jusqu'à la racine, vérifiant chaque InheritedElement pour une correspondance de type. Le premier InheritedElement correspondant est retourné. Cela signifie que l'InheritedWidget le plus proche dans l'arbre a priorité — vous pouvez remplacer les données à un niveau spécifique en plaçant InheritedWidget plus près des descendants.

dart
class ThemeData {
  final Color primaryColor;
  final TextTheme textTheme;

  const ThemeData({required this.primaryColor, required this.textTheme});
}

class MyTheme extends InheritedWidget {
  final ThemeData data;

  const MyTheme({required this.data, required Widget child}) : super(child: child);

  static MyTheme of(BuildContext context) {
    final widget = context.dependOnInheritedWidgetOfExactType<MyTheme>();
    assert(widget != null, "MyTheme not found in tree");
    return widget!;
  }

  @override
  bool updateShouldNotify(MyTheme oldWidget) => oldWidget.data != data;
}

Dans cet exemple, MyTheme utilise une méthode statique of pour fournir des données aux descendants. La méthode dependOnInheritedWidgetOfExactType enregistre une dépendance, et updateShouldNotify compare les anciennes et nouvelles données pour déterminer si les widgets dépendants doivent être reconstruits.

Créer un InheritedWidget personnalisé

Créer un InheritedWidget personnalisé consiste en deux étapes : définir une classe qui étend InheritedWidget, et implémenter une méthode statique of pour l'accès depuis les descendants. Les données sont transmises via le constructeur, et la méthode updateShouldNotify détermine quand les widgets dépendants doivent se reconstruire.

Étape 1 : Définir la classe InheritedWidget

La classe doit étendre InheritedWidget et accepter les données via un constructeur avec un paramètre child obligatoire. Les données peuvent être de n'importe quel type : primitifs, objets, fonctions. La règle principale est que les données doivent être immuables afin que les anciennes et nouvelles valeurs puissent être comparées de manière fiable.

Étape 2 : Méthode statique of

La méthode statique of prend BuildContext et retourne les données d'InheritedWidget. En interne, elle appelle dependOnInheritedWidgetOfExactType, qui trouve l'InheritedWidget le plus proche du type spécifié dans l'arbre. Si InheritedWidget n'est pas trouvé, la méthode lance une exception ou retourne une valeur par défaut selon l'implémentation.

Étape 3 : Utilisation dans les widgets

Pour accéder aux données, le widget appelle MyWidget.of(context) dans la méthode build. Flutter abonne automatiquement le widget aux mises à jour. Si les données changent, le widget se reconstruit dans l'image suivante. Cela permet un code propre et déclaratif sans paramètres inutiles.

dart
class UserPreferences extends InheritedWidget {
  final String languageCode;
  final bool darkMode;

  const UserPreferences({
    required this.languageCode,
    required this.darkMode,
    required Widget child,
  }) : super(child: child);

  static UserPreferences of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<UserPreferences>()!;
  }

  @override
  bool updateShouldNotify(UserPreferences oldWidget) =>
    oldWidget.languageCode != languageCode || oldWidget.darkMode != darkMode;
}

Dans cet exemple, UserPreferences stocke les préférences utilisateur. La méthode updateShouldNotify compare chaque champ individuellement, ce qui évite les reconstructions inutiles lorsqu'un seul paramètre change. Utilisez une approche similaire pour vos propres InheritedWidget avec plusieurs champs.

La méthode updateShouldNotify et la prévention des reconstructions inutiles

updateShouldNotify est la méthode clé d'InheritedWidget qui détermine si les widgets dépendants doivent être notifiés des changements de données. Si la méthode retourne false, les widgets dépendants ne se reconstruisent pas, même si InheritedWidget lui-même a reçu une nouvelle instance avec les mêmes données. C'est d'une importance cruciale pour les performances.

Implémentation correcte d'updateShouldNotify

Comparez uniquement les champs qui ont réellement changé et affectent l'affichage. Si InheritedWidget contient 10 champs mais qu'un seul affecte l'interface utilisateur, vérifiez uniquement ce champ. Pour les collections, utilisez une comparaison profonde ou des structures de données immuables. N'utilisez pas == pour List ou Map, car ils comparent par référence.

  • Primitifs — utilisez des comparaisons directes : oldWidget.value != value.
  • Objets immuables — utilisez == redéfini : oldWidget.data != data (si data redéfinit ==).
  • Collections — utilisez listEquals, mapEquals de package:flutter/foundation.dart.

Erreurs dans l'implémentation d'updateShouldNotify

L'erreur la plus courante est de retourner true sans comparaison. Cela entraîne la reconstruction de tous les widgets dépendants à chaque mise à jour du parent, même si les données n'ont pas changé. La deuxième erreur est de retourner false lorsque les données ont changé, ce qui conduit à une interface utilisateur obsolète. La troisième est une comparaison complexe qui s'exécute à chaque image et ralentit les performances.

InheritedWidget vs callbacks : que choisir?

InheritedWidget et les callbacks (passer des fonctions via les constructeurs) résolvent des problèmes différents. InheritedWidget est adapté aux données nécessaires à de nombreux widgets à différents niveaux de l'arbre. Les callbacks sont pratiques pour la transmission unidirectionnelle d'événements du parent à un enfant spécifique ou vice versa. Le choix dépend de l'architecture de l'application et de la fréquence des mises à jour.

Quand utiliser InheritedWidget

Utilisez InheritedWidget lorsque les données sont nécessaires à de nombreux widgets à différents niveaux d'imbrication : thème de l'application, préférences utilisateur, informations sur l'appareil, données de session actuelles. InheritedWidget est particulièrement efficace pour les données « globales » qui changent rarement mais sont nécessaires dans différentes parties de l'interface utilisateur.

Quand utiliser les callbacks

Les callbacks (fonctions de rappel) sont adaptés pour transmettre des événements d'un widget enfant à un parent : pression de bouton, sélection d'élément de liste, soumission de formulaire. Les callbacks indiquent explicitement quelles actions un enfant peut effectuer et ne créent pas de dépendances cachées. Pour transmettre des données vers le bas dans l'arbre sur un petit nombre de niveaux, il est également plus simple d'utiliser des paramètres de constructeur.

CritèreInheritedWidgetCallbacks
DirectionDu haut vers le bas (parent → descendants)Du bas vers le haut (enfant → parent) ou direct
PortéeSous-arbre entierWidget spécifique
ReconstructionAutomatique lors du changement de donnéesNécessite setState manuel
ComplexitéMoyenne (nécessite une classe InheritedWidget)Faible (juste une fonction)

InheritedWidget et les bibliothèques de gestion d'état

Provider et Riverpod sont des bibliothèques populaires de gestion d'état dans Flutter construites sur InheritedWidget. Elles étendent ses capacités : ajoutent le support de ChangeNotifier, la suppression automatique lors du démontage, l'initialisation paresseuse et une syntaxe simplifiée avec les génériques.

Provider basé sur InheritedWidget

Provider utilise InheritedWidget pour transmettre un objet de n'importe quel type vers le bas dans l'arbre. ChangeNotifierProvider suit les changements via ChangeNotifier et appelle updateShouldNotify lorsque notifyListeners est appelé. Cela libère le développeur de la création manuelle d'InheritedWidget et de l'implémentation d'updateShouldNotify.

Comparaison avec InheritedWidget direct

InheritedWidget direct donne plus de contrôle et ne nécessite pas de dépendances externes. Provider fournit une infrastructure prête : Consumer, Selector, MultiProvider, ProxyProvider. Le choix dépend de la complexité de l'application. Pour les projets simples, InheritedWidget direct est suffisant ; pour les grands, Provider ou Riverpod réduisent le code passe-partout.

dart
// InheritedWidget direct
class UserProvider extends InheritedWidget {
  final UserData userData;
  const UserProvider({required this.userData, required Widget child}) : super(child: child);
  static UserData of(BuildContext context) => context.dependOnInheritedWidgetOfExactType<UserProvider>()!.userData;
  @override
  bool updateShouldNotify(UserProvider old) => old.userData != userData;
}

// Équivalent Provider
return ChangeNotifierProvider<UserData>(
  create: (_) => UserData(),
  child: MyApp(),
);

Les deux approches dans l'exemple résolvent le même problème — transmettre UserData vers le bas dans l'arbre. Provider réduit le volume de code mais cache la mécanique d'InheritedWidget. InheritedWidget direct donne un contrôle total et une compréhension de ce qui se passe, ce qui est particulièrement important lors de l'apprentissage de Flutter et du débogage de problèmes complexes de reconstruction.

Foire aux questions

En quoi InheritedWidget diffère-t-il d'un widget ordinaire?

InheritedWidget rend les données disponibles pour tous les descendants via BuildContext, tandis qu'un widget ordinaire ne transmet les données que via le constructeur. InheritedWidget abonne également les descendants aux mises à jour des données.

À quelle fréquence les widgets dépendants se reconstruisent-ils?

Les widgets dépendants se reconstruisent uniquement lorsque updateShouldNotify retourne true. Si la méthode est correctement implémentée, la reconstruction se produit uniquement lorsque les données changent réellement, pas à chaque reconstruction du parent.

Peut-on utiliser plusieurs InheritedWidget dans le même arbre?

Oui, vous pouvez utiliser n'importe quel nombre d'InheritedWidget dans le même arbre. Chacun fournit des données d'un type spécifique, et les widgets peuvent obtenir des données de plusieurs InheritedWidget simultanément.

Quelle est la différence entre dependOnInheritedWidgetOfExactType et findAncestorWidgetOfExactType?

dependOn abonne le widget aux mises à jour — lorsque les données changent, le widget se reconstruit. findAncestor effectue une recherche unique sans abonnement, et le widget ne sera pas informé des changements de données.

InheritedWidget est-il adapté à la gestion d'état complexe?

Pour un état simple (thème, préférences) InheritedWidget est suffisant. Pour un état complexe avec logique métier, utilisez Provider, Riverpod ou BLoC — ils sont construits sur InheritedWidget et ajoutent l'infrastructure nécessaire.

Résumé

  • InheritedWidget est un widget spécial de Flutter pour transmettre des données vers le bas dans l'arbre avec abonnement automatique aux mises à jour.
  • Mécanisme de fonctionnement basé sur l'Element Tree : InheritedElement enregistre les éléments dépendants et les notifie des changements.
  • updateShouldNotify — la méthode clé pour éviter les reconstructions inutiles des widgets dépendants.
  • InheritedWidget intégrés : Theme, MediaQuery, Localizations, Directionality, DefaultTextStyle.
  • Création personnalisée inclut l'héritage de classe, la transmission de données via le constructeur et une méthode statique of.
  • Provider et Riverpod sont construits sur InheritedWidget et ajoutent ChangeNotifier, Consumer, Selector et une syntaxe simplifiée.
  • InheritedWidget résout le problème de prop drilling et est le fondement de la gestion d'état réactive dans Flutter.

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