InheritedWidget — o que é, passagem de dados na árvore e como funciona

Autor: IT Sectr Publicado: 2026-07-02 Tempo de leitura: 9 min

InheritedWidget é um widget especial no Flutter que passa dados para baixo na árvore de widgets sem passá-los explicitamente através de construtores. Widgets filhos acessam dados através do BuildContext e se inscrevem automaticamente nas atualizações. Quando os dados no InheritedWidget mudam, todos os widgets dependentes são reconstruídos. De acordo com Flutter API Reference, 2025, InheritedWidget está na base do Theme, MediaQuery, Localizations e da maioria das bibliotecas de gerenciamento de estado.

Pontos principais

  • InheritedWidget passa dados para baixo na Widget Tree sem precisar passá-los explicitamente por cada widget.
  • Inscrição automática — widgets que usam dependOnInheritedWidgetOfExactType são reconstruídos quando os dados mudam.
  • Theme e MediaQuery são exemplos integrados de InheritedWidget, disponíveis em todo aplicativo Flutter.
  • Provider e Riverpod são construídos sobre InheritedWidget e estendem suas capacidades para gerenciamento de estado.
  • Implementação correta requer sobrescrever updateShouldNotify para evitar reconstruções desnecessárias.

O que é InheritedWidget no Flutter?

InheritedWidget é um widget que torna seus dados disponíveis para todos os descendentes na Widget Tree. Ao contrário de um widget comum que apenas passa dados através de construtores para elementos filhos, InheritedWidget permite que qualquer widget na subárvore acesse os dados sem uma cadeia de parâmetros. Isso resolve o problema de “prop drilling” — passar dados através de muitos widgets intermediários que não usam esses dados por si só.

InheritedWidget integrados

Flutter inclui vários InheritedWidget integrados: Theme (esquema de cores e estilos), MediaQuery (tamanho da tela, orientação, densidade de pixels), Localizations (strings localizadas), Directionality (direção do texto), DefaultTextStyle (estilo de texto padrão). Esses widgets são definidos por widgets raiz como MaterialApp e estão disponíveis em todo o aplicativo.

Ciclo de vida do InheritedWidget

InheritedWidget não tem estado próprio — ele armazena dados passados pelo construtor. Quando o pai do InheritedWidget é reconstruído com novos dados, o método updateShouldNotify é chamado para comparar dados antigos e novos. Se o método retornar true, todos os widgets dependentes são marcados para reconstrução. Este é um mecanismo de atualização reativa simples, mas eficaz.

Como funciona a passagem de dados através do InheritedWidget

O mecanismo de passagem de dados através do InheritedWidget é baseado na Element Tree. Quando um widget chama dependOnInheritedWidgetOfExactType, o elemento correspondente registra uma dependência no InheritedElement. Quando InheritedWidget muda, InheritedElement notifica todos os elementos dependentes, que são reconstruídos no próximo quadro.

Registro de dependência

O método dependOnInheritedWidgetOfExactType não apenas encontra InheritedWidget na árvore — ele inscreve o elemento atual em notificações. Se você usasse findAncestorWidgetOfExactType em vez de dependOn, o widget obteria os dados, mas não seria reconstruído quando eles mudassem. Essa é uma diferença importante: dependOn é uma inscrição, findAncestor é uma busca única.

Percurso da árvore do InheritedWidget

Quando um widget solicita um InheritedWidget, o Flutter sobe pela Element Tree do elemento atual até a raiz, verificando cada InheritedElement para encontrar uma correspondência de tipo. O primeiro InheritedElement correspondente é retornado. Isso significa que o InheritedWidget mais próximo na árvore tem prioridade — você pode sobrescrever dados em um nível específico colocando InheritedWidget mais perto dos descendentes.

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

Neste exemplo, MyTheme usa um método estático of para fornecer dados aos descendentes. O método dependOnInheritedWidgetOfExactType registra uma dependência, e updateShouldNotify compara dados antigos e novos para determinar se os widgets dependentes precisam ser reconstruídos.

Criando um InheritedWidget personalizado

Criar um InheritedWidget personalizado consiste em duas etapas: definir uma classe que estenda InheritedWidget e implementar um método estático of para acesso dos descendentes. Os dados são passados através do construtor, e o método updateShouldNotify determina quando os widgets dependentes devem ser reconstruídos.

Passo 1: Definir a classe InheritedWidget

A classe deve estender InheritedWidget e aceitar dados através de um construtor com um parâmetro child obrigatório. Os dados podem ser de qualquer tipo: primitivos, objetos, funções. A regra principal é que os dados devem ser imutáveis para que os valores antigos e novos possam ser comparados de forma confiável.

Passo 2: Método estático of

O método estático of recebe BuildContext e retorna os dados do InheritedWidget. Internamente, ele chama dependOnInheritedWidgetOfExactType, que encontra o InheritedWidget mais próximo do tipo especificado na árvore. Se InheritedWidget não for encontrado, o método lança uma exceção ou retorna um valor padrão dependendo da implementação.

Passo 3: Uso em widgets

Para acessar os dados, o widget chama MyWidget.of(context) dentro do método build. O Flutter inscreve automaticamente o widget em atualizações. Se os dados mudarem, o widget é reconstruído no próximo quadro. Isso permite código limpo e declarativo sem parâmetros desnecessários.

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

Neste exemplo, UserPreferences armazena as configurações do usuário. O método updateShouldNotify compara cada campo individualmente, o que evita reconstruções desnecessárias quando apenas um parâmetro muda. Use uma abordagem semelhante para seus próprios InheritedWidget com vários campos.

O método updateShouldNotify e prevenção de reconstruções desnecessárias

updateShouldNotify é o método chave do InheritedWidget que determina se os widgets dependentes precisam ser notificados sobre mudanças nos dados. Se o método retornar false, os widgets dependentes não são reconstruídos, mesmo que o próprio InheritedWidget tenha recebido uma nova instância com os mesmos dados. Isso é criticamente importante para o desempenho.

Implementação correta do updateShouldNotify

Compare apenas os campos que realmente mudaram e afetam a exibição. Se InheritedWidget contém 10 campos, mas apenas um afeta a UI, verifique apenas esse campo. Para coleções, use comparação profunda ou estruturas de dados imutáveis. Não use == para List ou Map, pois eles comparam por referência.

  • Primitivos — use comparações diretas: oldWidget.value != value.
  • Objetos imutáveis — use == sobrescrito: oldWidget.data != data (se data sobrescreve ==).
  • Coleções — use listEquals, mapEquals de package:flutter/foundation.dart.

Erros na implementação do updateShouldNotify

O erro mais comum é retornar true sem comparação. Isso faz com que todos os widgets dependentes sejam reconstruídos em cada atualização do pai, mesmo que os dados não tenham mudado. O segundo erro é retornar false quando os dados mudaram, levando a uma UI desatualizada. O terceiro é uma comparação complexa que é executada a cada quadro e diminui o desempenho.

InheritedWidget vs callbacks: qual escolher?

InheritedWidget e callbacks (passar funções através de construtores) resolvem problemas diferentes. InheritedWidget é adequado para dados necessários por muitos widgets em diferentes níveis da árvore. Callbacks são convenientes para passagem unidirecional de eventos do pai para um filho específico ou vice-versa. A escolha depende da arquitetura do aplicativo e da frequência de atualizações.

Quando usar InheritedWidget

Use InheritedWidget quando os dados forem necessários para muitos widgets em diferentes níveis de aninhamento: tema do aplicativo, configurações do usuário, informações do dispositivo, dados da sessão atual. InheritedWidget é especialmente eficaz para dados “globais” que raramente mudam, mas são necessários em diferentes partes da UI.

Quando usar callbacks

Callbacks (funções de retorno de chamada) são adequados para passar eventos de um widget filho para o pai: pressionar botão, selecionar item de lista, enviar formulário. Callbacks indicam explicitamente quais ações um filho pode realizar e não criam dependências ocultas. Para passar dados para baixo na árvore por um pequeno número de níveis, também é mais simples usar parâmetros do construtor.

CritérioInheritedWidgetCallbacks
DireçãoDe cima para baixo (pai → descendentes)De baixo para cima (filho → pai) ou direto
EscopoSubárvore inteiraWidget específico
ReconstruçãoAutomática ao mudar dadosRequer setState manual
ComplexidadeMédia (requer classe InheritedWidget)Baixa (apenas uma função)

InheritedWidget e bibliotecas de gerenciamento de estado

Provider e Riverpod são bibliotecas populares de gerenciamento de estado no Flutter construídas sobre InheritedWidget. Elas estendem suas capacidades: adicionam suporte a ChangeNotifier, descarte automático ao desmontar, inicialização preguiçosa e sintaxe simplificada com genéricos.

Provider baseado em InheritedWidget

Provider usa InheritedWidget para passar um objeto de qualquer tipo para baixo na árvore. ChangeNotifierProvider rastreia mudanças através de ChangeNotifier e chama updateShouldNotify quando notifyListeners é chamado. Isso libera o desenvolvedor de criar manualmente InheritedWidget e implementar updateShouldNotify.

Comparação com InheritedWidget direto

InheritedWidget direto dá mais controle e não requer dependências externas. Provider fornece infraestrutura pronta: Consumer, Selector, MultiProvider, ProxyProvider. A escolha depende da complexidade do aplicativo. Para projetos simples, InheritedWidget direto é suficiente; para grandes, Provider ou Riverpod reduzem código repetitivo.

dart
// InheritedWidget direto
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 do Provider
return ChangeNotifierProvider<UserData>(
  create: (_) => UserData(),
  child: MyApp(),
);

Ambas as abordagens no exemplo resolvem o mesmo problema — passar UserData para baixo na árvore. Provider reduz o volume de código, mas esconde a mecânica do InheritedWidget. InheritedWidget direto dá controle total e compreensão do que está acontecendo, o que é especialmente importante ao aprender Flutter e depurar problemas complexos de reconstrução.

Perguntas frequentes

Como InheritedWidget difere de um widget comum?

InheritedWidget torna os dados disponíveis para todos os descendentes através do BuildContext, enquanto um widget comum apenas passa dados pelo construtor. InheritedWidget também inscreve os descendentes em atualizações de dados.

Com que frequência os widgets dependentes são reconstruídos?

Widgets dependentes são reconstruídos apenas quando updateShouldNotify retorna true. Se o método for implementado corretamente, a reconstrução ocorre apenas quando os dados realmente mudam, não em cada reconstrução do pai.

Vários InheritedWidget podem ser usados na mesma árvore?

Sim, você pode usar qualquer número de InheritedWidget na mesma árvore. Cada um fornece dados de um tipo específico, e os widgets podem obter dados de vários InheritedWidget simultaneamente.

Qual a diferença entre dependOnInheritedWidgetOfExactType e findAncestorWidgetOfExactType?

dependOn inscreve o widget em atualizações — quando os dados mudam, o widget é reconstruído. findAncestor realiza uma busca única sem inscrição, e o widget não saberá sobre mudanças nos dados.

InheritedWidget é adequado para gerenciamento de estado complexo?

Para estado simples (tema, configurações) InheritedWidget é suficiente. Para estado complexo com lógica de negócios, use Provider, Riverpod ou BLoC — eles são construídos sobre InheritedWidget e adicionam a infraestrutura necessária.

Resumo

  • InheritedWidget é um widget especial do Flutter para passar dados para baixo na árvore com inscrição automática em atualizações.
  • Mecanismo de funcionamento baseado na Element Tree: InheritedElement registra elementos dependentes e os notifica sobre mudanças.
  • updateShouldNotify — o método chave para prevenir reconstruções desnecessárias de widgets dependentes.
  • InheritedWidget integrados: Theme, MediaQuery, Localizations, Directionality, DefaultTextStyle.
  • Criar personalizado inclui herança de classe, passagem de dados pelo construtor e um método estático of.
  • Provider e Riverpod são construídos sobre InheritedWidget e adicionam ChangeNotifier, Consumer, Selector e sintaxe simplificada.
  • InheritedWidget resolve o problema de prop drilling e é a base do gerenciamento de estado reativo no Flutter.

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também