2. Flutter: StatelessWidget, StatefulWidget e Ciclos de Vida
Qual seria a diferença entre StatelessWidget e StatefulWidget? Como eles nascem?

StatelessWidget
Os componentes Stateless não tem estado, são estáticos, ou seja, depois de carregado não consegue mais atualizar o estado.
import 'package:flutter/material.dart';
void main() {
runApp(HomePageStateless());
}
class HomePageStateless extends StatelessWidget {
String texto = 'Olá';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Text(texto),
floatingActionButton: FloatingActionButton(
onPressed: () {
texto = 'Cliquei no Floating Button';
}),
),
);
}
}
O MaterialApp()
é o componente principal do Flutter, onde você coloca as rotas, themas e tudo que você precisa para trabalhar seu aplicativo.
O Scaffold()
é o widget principal para montar nossa tela, se não o colocarmos, a tela ficará com uma aparência escura. É nesse componente que existe o AppBar(),
aquela barra que fica lá em cima do app, entre outras coisas que ele gerencia para que você possa usar em seu aplicativo.
Observe que no código de exemplo acima o bottão criado "Floating Action Button" realiza a ação de alterar a variável String texto
, porém irá apresentar algumas informações:
- Como o StatelessWidget é um componente imutável suas variáveis devem também ser, então irá pedir para que você coloque suas variáveis como
final;
Ao atribuirmos o modificador
final
a variávelString texto
, ocorrerá outro erro que aparecerá na função executada ao clicar nofloatingActionButton,
pois, se a variável é imutável, não se pode alterá-la, por isso irá aparecer tal erro.
Percebe-se que não tem como alterar, em regra, o estado de um StatelessWidget.
StatefulWidget
É o componente mutável de flutter:
import 'package:flutter/material.dart';
void main() {
runApp(HomePageStateful());
}
class HomePageStateful extends StatefulWidget {
@override
_HomePageStatefulState createState() => _HomePageStatefulState();
}
class _HomePageStatefulState extends State {
String texto = 'Olá';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Text(texto),
floatingActionButton: FloatingActionButton(
onPressed: () {
texto = 'Cliquei no Floating Button';
}),
),
);
}
}
Pronto, mas, mesmo assim se eu clicar no botão não irá ocorrer nada, pois o StatefulWidget disponibiliza uma função setState()
que é a responsável para que eu possa alterar o estado da aplicação, que seria alterar a variável String texto
.
import 'package:flutter/material.dart';
void main() {
runApp(HomePageStateful());
}
class HomePageStateful extends StatefulWidget {
@override
_HomePageStatefulState createState() => _HomePageStatefulState();
}
class _HomePageStatefulState extends State {
String texto = 'Olá';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Text(texto),
floatingActionButton: FloatingActionButton(onPressed: () {
setState(() {
texto = 'Cliquei no Floating Button';
});
}),
),
);
}
}
No StatelessWidget não existe esta função anônima chamada setState().
Esta é a diferença básica entre estes dos componentes. Para ver o código acima em execução entre aqui no DartPad.
Clico de Vida dos Compontens
O componente StatelessWidget a partir do momento que é chamado ele executa o ciclo:
StatelessWidget -> constructor -> build
Já o StatefulWidget funciona da seguinte forma:
StatefulWidget - > createState() -> constructor -> initState() -> didChangeDependencies() -> build -> setState() -> build
build
Sempre que for necessário reconstruir um componente, o build será chamado.
initState()
É invocado somente uma vez e serve para que, antes de construir a tela, possa alimentar os estados do jeito que você precisa. Porém, como a tela ainda não foi montada, não existe aqui o BuildContext context
, então não poderia abrir uma tela, por exemplo.
didChangeDependencies()
Após o initState()
é executado o didChangeDependencies()
onde também pode ser feito a alteração do estado, também somente é chamado uma vez.
setState()
O StatefulWidget, como vimos no início do artigo, tem o setState()
que serve para atualizar a tela ou notificar o widget sobre a alteração que houve e quando nos o acionamos, ele invoca outro método o didUpdateWidget() e por último o build.
didUpdateWidget()
É o método chamado quando o "pai" dele é reconstruído, fazendo com que seja reconstruído o componente filho também, porém será chamado o didUpdateWidget()
, mas somente ocorre se o Widget "pai" for reconstruído e não se o Widget "filho" for reconstruído.
@override
void didUpdateWidget(HomePageStateful oldWidget) {
super.didUpdateWidget(oldWidget);
print('didUpdateWidget');
}
Mas para que serve? Geralmente quando se quer resetar um valor inicial de algo, uma varável, por exemplo.
dispose()
A última parte do ciclo de vida é feito para limpeza e é necessário quando há stream ou controladores e se é necessário chamar o close() dele, evitando assim o uso excessivo da memória, veremos mais a respeito dele mais a frente.
Só é chamado quando a página, pilha, que você está sair da memória, quando o componente deixar de existir.