StatefulWidget: o que é, ciclo de vida e princípio de funcionamento

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

StatefulWidget é um widget Flutter com estado mutável, permitindo que a UI reaja a ações do usuário, eventos assíncronos e fluxos de dados. De acordo com a documentação oficial do Flutter (Flutter.dev, 2026), o StatefulWidget é usado para todos os elementos interativos da aplicação: formulários de entrada, animações, caixas de seleção, interruptores e telas que carregam dados da rede. Ao contrário do StatelessWidget, ele cria um objeto State separado que persiste durante todo o seu ciclo de vida e pode ser reconstruído sem recriar o próprio widget.

Principais pontos

  • StatefulWidget é um widget que pode alterar seu estado durante a execução, acionando a reconstrução da UI através de setState
  • Ciclo de vida — StatefulWidget passa pelos estágios createState, initState, didChangeDependencies, build, didUpdateWidget, dispose
  • Objeto State é um objeto separado que armazena o estado e existe independentemente do widget durante toda a sua vida
  • setState é a única forma legítima de notificar o Flutter sobre a necessidade de reconstruir o widget após a alteração de dados
  • Desempenho — o uso excessivo de StatefulWidget aumenta o consumo de memória e o tempo de renderização

O que é StatefulWidget?

StatefulWidget é uma classe Flutter que pode alterar seu estado em resposta a ações do usuário, eventos do sistema ou operações assíncronas. Ao contrário do StatelessWidget, o StatefulWidget não é renderizado diretamente — ele cria um objeto State que cuida da renderização. Essa separação em duas classes (Widget e State) permite que o Flutter reconstrua a UI sem recriar o próprio widget, proporcionando uma vantagem significativa de desempenho durante atualizações frequentes.

A arquitetura do StatefulWidget segue o padrão de “separação do mutável e do imutável”: o widget em si permanece imutável (como StatelessWidget), enquanto todo o estado mutável é armazenado em um objeto State separado. Isso permite que o Flutter reutilize widgets comparando-os por tipo e Key, preservando ao mesmo tempo o estado real entre reconstruções.

De acordo com o Google (Flutter Architectural Overview, 2026), o StatefulWidget é ideal para cenários onde o estado muda mais de uma vez durante a vida do widget: campos de texto, animações, temporizadores, fluxos de dados, cargas assíncronas. Para inicialização única, o StatelessWidget é suficiente.

Quando o StatefulWidget é necessário

StatefulWidget é obrigatório quando o widget precisa responder a eventos externos: cliques em botões, conclusão de requisições HTTP, atualizações de dados do banco de dados, assinaturas WebSocket. Também é necessário para widgets com animações, campos de texto com controladores e componentes que gerenciam foco. Se um widget apenas exibe dados e não gera eventos, use StatelessWidget.

Estrutura interna

StatefulWidget consiste em duas classes: o próprio StatefulWidget (leve, imutável) e State (pesado, mutável). O framework cria State através do método createState(), chamado uma vez ao ser inserido na árvore. State recebe uma referência ao widget através da propriedade widget e pode acessar seus campos em qualquer ponto do ciclo de vida.

Ciclo de vida do StatefulWidget

O ciclo de vida do StatefulWidget consiste em seis estágios principais, cada um fornecendo um método sobrescritível para realizar tarefas específicas. Compreender esses estágios é fundamental para o gerenciamento adequado de recursos e evitar vazamentos de memória.

createState

createState é o primeiro método do ciclo de vida, chamado quando o StatefulWidget é inserido na árvore. Ele deve retornar uma nova instância de State associada a este widget. Este método é chamado exatamente uma vez durante toda a vida do elemento. É importante não realizar operações pesadas aqui — o createState deve ser o mais leve possível.

initState

initState é chamado imediatamente após a criação do State, antes da primeira construção da UI. Aqui são realizadas: inicialização de controladores (TextEditingController, AnimationController), assinatura de fluxos de dados (StreamSubscription), configuração de temporizadores e inicialização de campos. De acordo com a documentação do Flutter (Flutter.dev, 2026), não é possível chamar BuildContext.of() no initState — a árvore ainda não está totalmente montada.

didChangeDependencies

didChangeDependencies é chamado após initState e sempre que as dependências de InheritedWidget mudam. Este é um local adequado para chamar MediaQuery.of(context) ou assinar o Theme — valores que podem mudar durante a execução da aplicação. Se um widget usa InheritedWidget, a lógica de inicialização deve estar aqui, não no initState.

build e didUpdateWidget

build é o método principal que retorna a árvore de widgets. Ele é chamado após initState, após didChangeDependencies e após cada setState. didUpdateWidget é chamado quando o pai é reconstruído e passa um StatefulWidget com novos parâmetros. Aqui é possível comparar os campos antigos e novos do widget e, se necessário, atualizar o estado.

dispose

dispose é o estágio final do ciclo de vida. Aqui todos os recursos são liberados: assinaturas de fluxos são canceladas, controladores são removidos, temporizadores são cancelados. Não chamar dispose leva a vazamentos de memória. Após o dispose, o State é considerado morto — chamar setState dentro dele lança uma exceção.

Como funciona o StatefulWidget?

O mecanismo de funcionamento do StatefulWidget é baseado no trabalho coordenado de três entidades: Widget (descrição leve), Element (camada intermediária) e State (armazenamento de dados). Quando o Flutter encontra um StatefulWidget na descrição, ele cria um StatefulElement, que chama createState e armazena uma referência ao objeto State. Quando o pai é reconstruído, o Flutter compara o novo widget com o Element atual — se o tipo e a Key coincidirem, o Element é atualizado e o State permanece o mesmo.

O estado só é alterado através da chamada setState, que notifica o framework sobre a necessidade de reconstrução. É importante entender: o setState não altera o estado automaticamente — ele apenas marca o widget como “su”. O desenvolvedor atualiza independentemente os campos do State no callback passado para setState. Após a conclusão do callback, o Flutter chama build e atualiza a UI.

De acordo com a equipe Dart/Flutter (Dart Language Specification, 2026), essa separação garante que todas as alterações de estado ocorram sincronamente antes da chamada de build, eliminando a situação em que a UI exibe dados parcialmente atualizados. Este é um mecanismo chave de consistência da interface no Flutter.

Exemplos de código em Dart

Vamos ver um StatefulWidget simples — um contador de cliques em botão. Ele demonstra o padrão básico: criação de State, inicialização de um campo no initState, alteração via setState:

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

  @override
  State<CounterScreen> createState() => _CounterScreenState();
}

class _CounterScreenState extends State<CounterScreen> {
  int _count = 0;

  void _increment() {
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Count: $_count'),
        ElevatedButton(
          onPressed: _increment,
          child: const Text('Incrementar'),
        ),
      ],
    );
  }
}

Um exemplo com carregamento assíncrono de dados e gerenciamento de ciclo de vida. StatefulWidget carrega dados da rede e exibe o estado de carregamento:

dart
class UserProfilePage extends StatefulWidget {
  final String userId;
  const UserProfilePage({super.key, required this.userId});

  @override
  State<UserProfilePage> createState() => _UserProfilePageState();
}

class _UserProfilePageState extends State<UserProfilePage> {
  UserModel? _user;
  bool _isLoading = true;

  @override
  void initState() {
    super.initState();
    _loadUser();
  }

  Future<void> _loadUser() async {
    final user = await UserService.fetchUser(widget.userId);
    setState(() {
      _user = user;
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_isLoading) return const CircularProgressIndicator();
    return Text('Olá, ${_user!.name}');
  }
}

No segundo exemplo, é importante notar: initState inicia uma operação assíncrona, mas o método em si não é assíncrono. A assincronia é implementada via async/await dentro de um método separado _loadUser, que atualiza o estado via setState após a conclusão da requisição. Essa abordagem garante que o widget exiba corretamente o indicador de carregamento antes de receber os dados.

StatefulWidget vs StatelessWidget

A escolha entre StatefulWidget e StatelessWidget não se trata apenas de ter estado. O StatefulWidget fornece um ciclo de vida completo com os métodos initState, didChangeDependencies, didUpdateWidget e dispose, que são necessários para trabalhar com controladores, animações e fluxos. O StatelessWidget, por outro lado, não possui esses métodos e é sempre mais leve para o framework.

A recomendação da equipe Flutter (Flutter docs, 2026) é minimizar o número de StatefulWidgets em uma aplicação, elevando o estado para cima na árvore (State Hoisting) ou usando soluções de gerenciamento de estado (Riverpod, Bloc, Provider). Cada StatefulWidget cria um objeto State que vive até que o elemento seja removido — quanto mais desses widgets, maior a carga de memória.

CritérioStatefulWidgetStatelessWidget
EstadoMutávelImutável
Ciclo de vida6 estágiosApenas build
Objeto StateCriado separadamenteNão necessário
setStateDisponívelNão disponível
AssinaturasinitState/disposeNão suportadas
Construtor constLimitadoTotalmente suportado
Consumo de memóriaMaiorMenor

Desempenho e otimização

StatefulWidget requer mais recursos que StatelessWidget devido à necessidade de criar e manter um objeto State. No entanto, o uso correto do StatefulWidget não causa problemas de desempenho se algumas regras forem seguidas. Primeiro, evite aninhamento profundo de StatefulWidget — cada nível adiciona sobrecarga à travessia da árvore. Segundo, divida um StatefulWidget complexo em vários simples, cada um responsável por sua própria parte do estado.

De acordo com a pesquisa de desempenho do Flutter (Flutter.dev, fevereiro de 2026), a causa mais comum de quedas de FPS é chamar setState em um widget pai que reconstrói todos os descendentes, incluindo StatelessWidgets que não alteraram sua exibição. A solução é extrair a parte mutável da UI para um StatefulWidget separado para que setState reconstrua apenas os widgets mínimos necessários.

Usar const dentro de State é outra técnica importante. Se os widgets filhos forem declarados como const, o Flutter não os reconstruirá quando setState for chamado no pai. Isso reduz a carga no framework e diminui o tempo de renderização do quadro.

Evite setState frequente

Cada chamada setState desencadeia uma reconstrução completa do widget. Se o estado mudar com alta frequência (por exemplo, animação ou fluxo de dados), considere usar AnimatedBuilder, ValueListenableBuilder ou StreamBuilder em vez de chamar setState manualmente. Esses widgets otimizam a reconstrução, atualizando apenas a parte da UI que realmente mudou.

Erros comuns

O primeiro erro comum com StatefulWidget é chamar setState após dispose. Quando um widget é removido da árvore, o State é considerado morto, e qualquer chamada setState lança uma exceção “setState called after dispose”. Isso acontece mais frequentemente quando uma operação assíncrona termina após a remoção do widget. A solução é verificar a flag mounted antes de chamar setState ou cancelar operações assíncronas no dispose.

O segundo erro é realizar cálculos pesados no método build. Como build é chamado em cada setState e em cada reconstrução do pai, todos os cálculos devem ser os mais leves possível. Se uma operação intensiva em recursos for necessária, mova-a para um Isolate separado ou armazene em cache o resultado em um campo de State.

O terceiro erro é não chamar super.initState() e super.dispose(). Ao sobrescrever esses métodos, o desenvolvedor deve chamar a implementação do pai. Caso contrário, o framework não conseguirá gerenciar corretamente o estado do Element, levando a bugs difíceis de rastrear.

Recomendações para evitar erros

  • Sempre verifique mounted antes de setState em callbacks assíncronos
  • Não se esqueça de chamar super.initState() e super.dispose()
  • Não faça requisições HTTP diretamente no build — use initState
  • Cancele todas as assinaturas no dispose
  • Use o mínimo de StatefulWidgets no seu projeto

Perguntas frequentes

Qual a diferença entre StatefulWidget e StatelessWidget?

StatefulWidget pode alterar seu estado via setState, tem um ciclo de vida (initState, dispose) e cria um objeto State separado. StatelessWidget não pode alterar o estado e não tem métodos de ciclo de vida — ele simplesmente exibe os dados recebidos.

Quantas vezes o createState é chamado?

createState é chamado exatamente uma vez para cada instância de StatefulElement. Mesmo que o pai seja reconstruído várias vezes, enquanto o tipo e a Key do widget não mudarem, createState não é chamado — o objeto State existente é usado.

O que acontece se dispose não for chamado?

Os recursos não serão liberados: os controladores continuarão funcionando em segundo plano, as assinaturas de fluxos permanecerão ativas, os temporizadores não serão cancelados. Isso leva a vazamentos de memória e pode causar chamadas setState após dispose, o que lança uma exceção.

StatefulWidget pode ser const?

Sim, o construtor do StatefulWidget pode ser const. No entanto, isso não oferece o mesmo benefício que para StatelessWidget — o objeto State ainda será criado na primeira inserção. const afeta apenas o widget em si (o invólucro leve), não o State.

Para que serve o método didUpdateWidget?

didUpdateWidget é chamado quando o pai passa um StatefulWidget com novos parâmetros. Isso é necessário para sincronizar o estado com os novos dados — por exemplo, se o userId nos parâmetros mudou, o perfil do novo usuário precisa ser carregado.

Resumo

  • StatefulWidget é um widget com estado mutável, usando um objeto State separado para armazenar dados e gerenciar o ciclo de vida
  • Ciclo de vida consiste em createState, initState, didChangeDependencies, build, didUpdateWidget e dispose, cada um com seu próprio propósito
  • setState é a única forma legítima de notificar o framework sobre uma mudança de estado, após a qual build é chamado automaticamente
  • mounted é uma flag que deve ser verificada antes de chamar setState em operações assíncronas para evitar uma exceção após dispose
  • Desempenho — StatefulWidget requer mais recursos que StatelessWidget; recomenda-se minimizar sua quantidade elevando o estado para camadas externas
  • Widgets filhos const dentro de State ajudam a reduzir a quantidade de reconstrução quando setState é chamado, melhorando o desempenho
  • Escolha correta — use StatefulWidget apenas quando o widget precisar gerenciar dados mutáveis ou operações assíncronas

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