InheritedWidget — cos'è, passaggio di dati nell'albero e come funziona

Autore: IT Sectr Pubblicato: 2026-07-02 Tempo di lettura: 9 min

InheritedWidget è un widget speciale in Flutter che passa dati verso il basso nell'albero dei widget senza passarli esplicitamente attraverso i costruttori. I widget figli accedono ai dati tramite BuildContext e si iscrivono automaticamente agli aggiornamenti. Quando i dati in InheritedWidget cambiano, tutti i widget dipendenti vengono ricostruiti. Secondo Flutter API Reference, 2025, InheritedWidget è alla base di Theme, MediaQuery, Localizations e della maggior parte delle librerie di gestione dello stato.

Punti chiave

  • InheritedWidget passa dati verso il basso nell'albero Widget Tree senza passarli esplicitamente attraverso ogni widget.
  • Iscrizione automatica — i widget che usano dependOnInheritedWidgetOfExactType vengono ricostruiti quando i dati cambiano.
  • Theme e MediaQuery sono esempi incorporati di InheritedWidget, disponibili in ogni applicazione Flutter.
  • Provider e Riverpod sono costruiti sopra InheritedWidget e ne estendono le capacità per la gestione dello stato.
  • Implementazione corretta richiede la sovrascrittura di updateShouldNotify per prevenire ricostruzioni non necessarie.

Cos'è InheritedWidget in Flutter?

InheritedWidget è un widget che rende i suoi dati disponibili a tutti i discendenti nell'albero Widget Tree. A differenza di un widget normale che passa dati solo attraverso i costruttori agli elementi figli, InheritedWidget permette a qualsiasi widget nel sottoalbero di accedere ai dati senza una catena di parametri. Questo risolve il problema del “prop drilling” — passare dati attraverso molti widget intermedi che non usano questi dati stessi.

InheritedWidget incorporati

Flutter include diversi InheritedWidget incorporati: Theme (schema di colori e stili), MediaQuery (dimensioni schermo, orientamento, densità pixel), Localizations (stringhe localizzate), Directionality (direzione del testo), DefaultTextStyle (stile testo predefinito). Questi widget sono impostati da widget radice come MaterialApp e sono disponibili in tutta l'applicazione.

Ciclo di vita di InheritedWidget

InheritedWidget non ha uno stato proprio — memorizza i dati passati attraverso il costruttore. Quando il genitore di InheritedWidget viene ricostruito con nuovi dati, il metodo updateShouldNotify viene chiamato per confrontare dati vecchi e nuovi. Se il metodo restituisce true, tutti i widget dipendenti vengono marcati per la ricostruzione. Questo è un meccanismo di aggiornamento reattivo semplice ma efficace.

Come funziona il passaggio di dati attraverso InheritedWidget

Il meccanismo di passaggio dati attraverso InheritedWidget si basa sull'Element Tree. Quando un widget chiama dependOnInheritedWidgetOfExactType, l'elemento corrispondente registra una dipendenza su InheritedElement. Quando InheritedWidget cambia, InheritedElement notifica tutti gli elementi dipendenti, che vengono ricostruiti nel fotogramma successivo.

Registrazione della dipendenza

Il metodo dependOnInheritedWidgetOfExactType non solo trova InheritedWidget nell'albero — iscrive l'elemento corrente alle notifiche. Se usassi findAncestorWidgetOfExactType invece di dependOn, il widget otterrebbe i dati ma non verrebbe ricostruito quando cambiano. Questa è una differenza importante: dependOn è un'iscrizione, findAncestor è una ricerca una tantum.

Attraversamento dell'albero di InheritedWidget

Quando un widget richiede un InheritedWidget, Flutter risale l'Element Tree dall'elemento corrente fino alla radice, controllando ogni InheritedElement per una corrispondenza di tipo. Il primo InheritedElement corrispondente viene restituito. Ciò significa che l'InheritedWidget più vicino nell'albero ha priorità — puoi sovrascrivere i dati a un livello specifico posizionando InheritedWidget più vicino ai discendenti.

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;
}

In questo esempio, MyTheme usa un metodo statico of per fornire dati ai discendenti. Il metodo dependOnInheritedWidgetOfExactType registra una dipendenza, e updateShouldNotify confronta dati vecchi e nuovi per determinare se i widget dipendenti devono essere ricostruiti.

Creare un InheritedWidget personalizzato

Creare un InheritedWidget personalizzato consiste in due passaggi: definire una classe che estende InheritedWidget e implementare un metodo statico of per l'accesso dai discendenti. I dati vengono passati attraverso il costruttore e il metodo updateShouldNotify determina quando i widget dipendenti devono essere ricostruiti.

Passo 1: Definire la classe InheritedWidget

La classe deve estendere InheritedWidget e accettare dati attraverso un costruttore con un parametro child obbligatorio. I dati possono essere di qualsiasi tipo: primitivi, oggetti, funzioni. La regola principale è che i dati devono essere immutabili in modo che i valori vecchi e nuovi possano essere confrontati in modo affidabile.

Passo 2: Metodo statico of

Il metodo statico of prende BuildContext e restituisce i dati di InheritedWidget. Internamente, chiama dependOnInheritedWidgetOfExactType, che trova l'InheritedWidget più vicino del tipo specificato nell'albero. Se InheritedWidget non viene trovato, il metodo lancia un'eccezione o restituisce un valore predefinito a seconda dell'implementazione.

Passo 3: Utilizzo nei widget

Per accedere ai dati, il widget chiama MyWidget.of(context) all'interno del metodo build. Flutter iscrive automaticamente il widget agli aggiornamenti. Se i dati cambiano, il widget viene ricostruito nel fotogramma successivo. Questo permette codice pulito e dichiarativo senza parametri non necessari.

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;
}

In questo esempio, UserPreferences memorizza le preferenze dell'utente. Il metodo updateShouldNotify confronta ogni campo individualmente, prevenendo ricostruzioni non necessarie quando solo un parametro cambia. Usa un approccio simile per i tuoi InheritedWidget personalizzati con più campi.

Il metodo updateShouldNotify e la prevenzione di ricostruzioni non necessarie

updateShouldNotify è il metodo chiave di InheritedWidget che determina se i widget dipendenti devono essere notificati sui cambiamenti dei dati. Se il metodo restituisce false, i widget dipendenti non vengono ricostruiti, anche se InheritedWidget stesso ha ricevuto una nuova istanza con gli stessi dati. Questo è criticamente importante per le prestazioni.

Implementazione corretta di updateShouldNotify

Confronta solo i campi che sono effettivamente cambiati e influenzano la visualizzazione. Se InheritedWidget contiene 10 campi ma solo uno influenza l'interfaccia utente, controlla solo quel campo. Per le collezioni, usa un confronto profondo o strutture dati immutabili. Non usare == per List o Map, poiché confrontano per riferimento.

  • Primitivi — usa confronti diretti: oldWidget.value != value.
  • Oggetti immutabili — usa == sovrascritto: oldWidget.data != data (se data sovrascrive ==).
  • Collezioni — usa listEquals, mapEquals da package:flutter/foundation.dart.

Errori nell'implementazione di updateShouldNotify

L'errore più comune è restituire true senza confronto. Questo causa la ricostruzione di tutti i widget dipendenti a ogni aggiornamento del genitore, anche se i dati non sono cambiati. Il secondo errore è restituire false quando i dati sono cambiati, portando a un'interfaccia utente obsoleta. Il terzo è un confronto complesso che viene eseguito ogni fotogramma e rallenta le prestazioni.

InheritedWidget vs callback: cosa scegliere?

InheritedWidget e callback (passare funzioni attraverso i costruttori) risolvono problemi diversi. InheritedWidget è adatto per dati necessari a molti widget a diversi livelli dell'albero. I callback sono convenienti per il passaggio unidirezionale di eventi dal genitore a un figlio specifico o viceversa. La scelta dipende dall'architettura dell'applicazione e dalla frequenza degli aggiornamenti.

Quando usare InheritedWidget

Usa InheritedWidget quando i dati sono necessari a molti widget a diversi livelli di annidamento: tema dell'app, preferenze utente, informazioni sul dispositivo, dati della sessione corrente. InheritedWidget è particolarmente efficace per dati “globali” che cambiano raramente ma sono necessari in diverse parti dell'interfaccia utente.

Quando usare callback

I callback (funzioni di richiamo) sono adatti per passare eventi da un widget figlio a un genitore: pressione di un pulsante, selezione di un elemento di elenco, invio di un modulo. I callback indicano esplicitamente quali azioni un figlio può eseguire e non creano dipendenze nascoste. Per passare dati verso il basso attraverso un piccolo numero di livelli, è anche più semplice usare parametri del costruttore.

CriterioInheritedWidgetCallback
DirezioneDall'alto verso il basso (genitore → discendenti)Dal basso verso l'alto (figlio → genitore) o diretta
AmbitoIntero sottoalberoWidget specifico
RicostruzioneAutomatica al cambiamento dei datiRichiede setState manuale
ComplessitàMedia (richiede classe InheritedWidget)Bassa (solo una funzione)

InheritedWidget e librerie di gestione dello stato

Provider e Riverpod sono librerie popolari di gestione dello stato in Flutter costruite sopra InheritedWidget. Estendono le sue capacità: aggiungono supporto ChangeNotifier, smaltimento automatico allo smontaggio, inizializzazione pigra e sintassi semplificata con i generics.

Provider basato su InheritedWidget

Provider usa InheritedWidget per passare un oggetto di qualsiasi tipo verso il basso nell'albero. ChangeNotifierProvider traccia i cambiamenti attraverso ChangeNotifier e chiama updateShouldNotify quando viene chiamato notifyListeners. Questo libera lo sviluppatore dalla creazione manuale di InheritedWidget e dall'implementazione di updateShouldNotify.

Confronto con InheritedWidget diretto

InheritedWidget diretto dà più controllo e non richiede dipendenze esterne. Provider fornisce infrastruttura pronta: Consumer, Selector, MultiProvider, ProxyProvider. La scelta dipende dalla complessità dell'applicazione. Per progetti semplici, InheritedWidget diretto è sufficiente; per progetti grandi, Provider o Riverpod riducono il codice boilerplate.

dart
// InheritedWidget diretto
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;
}

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

Entrambi gli approcci nell'esempio risolvono lo stesso problema — passare UserData verso il basso nell'albero. Provider riduce il volume di codice ma nasconde la meccanica di InheritedWidget. InheritedWidget diretto dà controllo completo e comprensione di ciò che accade, particolarmente importante quando si impara Flutter e si debuggano problemi complessi di ricostruzione.

Domande frequenti

In cosa differisce InheritedWidget da un widget normale?

InheritedWidget rende i dati disponibili a tutti i discendenti attraverso BuildContext, mentre un widget normale passa dati solo attraverso il costruttore. InheritedWidget iscrive anche i discendenti agli aggiornamenti dei dati.

Con quale frequenza vengono ricostruiti i widget dipendenti?

I widget dipendenti vengono ricostruiti solo quando updateShouldNotify restituisce true. Se il metodo è implementato correttamente, la ricostruzione avviene solo quando i dati cambiano effettivamente, non a ogni ricostruzione del genitore.

Si possono usare più InheritedWidget nello stesso albero?

Sì, puoi usare qualsiasi numero di InheritedWidget nello stesso albero. Ognuno fornisce dati di un tipo specifico e i widget possono ottenere dati da più InheritedWidget contemporaneamente.

Qual è la differenza tra dependOnInheritedWidgetOfExactType e findAncestorWidgetOfExactType?

dependOn iscrive il widget agli aggiornamenti — quando i dati cambiano, il widget viene ricostruito. findAncestor esegue una ricerca una tantum senza iscrizione e il widget non saprà dei cambiamenti dei dati.

InheritedWidget è adatto per la gestione di stato complessa?

Per stato semplice (tema, impostazioni) InheritedWidget è sufficiente. Per stato complesso con logica di business, usa Provider, Riverpod o BLoC — sono costruiti su InheritedWidget e aggiungono l'infrastruttura necessaria.

Riepilogo

  • InheritedWidget è un widget speciale di Flutter per passare dati verso il basso nell'albero con iscrizione automatica agli aggiornamenti.
  • Meccanismo di funzionamento basato sull'Element Tree: InheritedElement registra elementi dipendenti e li notifica dei cambiamenti.
  • updateShouldNotify — il metodo chiave per prevenire ricostruzioni non necessarie dei widget dipendenti.
  • InheritedWidget incorporati: Theme, MediaQuery, Localizations, Directionality, DefaultTextStyle.
  • Creazione personalizzata include ereditarietà di classe, passaggio dati tramite costruttore e un metodo statico of.
  • Provider e Riverpod sono costruiti su InheritedWidget e aggiungono ChangeNotifier, Consumer, Selector e sintassi semplificata.
  • InheritedWidget risolve il problema del prop drilling ed è il fondamento della gestione dello stato reattiva in Flutter.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche