3. Flutter: Gerenciador de Estado: setState()

Iremos falar na principal gerencia de estado do Flutter e explicar uma forma inteligente de aplicá-lo

3. Flutter: Gerenciador de Estado: setState()

Para se trabalhar com o setState() nós precisamos de um componente Stateful, pois este componente irá guardar o estado (tudo aquilo que iremos atualizar) para nosso aplicativo.

Vamos criar um aplicativo simples para começar a entender setState():

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        home: MyHomePage(),
        routes: {'/setState': (_) => SetState()});
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("FlutterBrasil"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            RaisedButton(
              onPressed: () {
                Navigator.of(context).pushNamed('/setState');
              },
              child: Text("Ir para SetState"),
            )
          ],
        ),
      ),
    );
  }
}

class SetState extends StatefulWidget {
  @override
  _MySetState createState() => _MySetState();
}

class _MySetState extends State {
  String nome = "Flutter";
  @override
  Widget build(BuildContext context) {
    print('build');
    return Scaffold(
      appBar: AppBar(
        title: Text("FlutterBrasil"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(nome),
            RaisedButton(
              onPressed: () {
                setState(() {
                  nome = "Brasil";
                });
              },
              child: Text("alterar nome"),
            )
          ],
        ),
      ),
    );
  }
}

Basicamente, criamos um app em que na primeira tela MyHomePage() tem um botão que nos leva a segunda tela SetState() que tem um Text('Flutter') que é alterado quando se clica no RaisedButton() e para isso é utilizado o setState().

Toda vez que se chama o setState() é feito a reconstrução de tudo que está em Widget build (BuildContext context), por exemplo, no código acima, toda vez que você clica no "alterar nome" é refeito a tela SetState() (segunda tela). 

Para outras linguagens, isso pode ser um grande problema, mas para o Flutter, por ter uma boa performace, veja aqui o por que, não irá ter tanto problema em uma aplicação muito simples.

Como "resolver" esse rebuild?

Modificador const

Para diminuir a reconstrução de widgets, basta colocar no widget que você não quer que seja reconstruído o const, como no título da página, em textos que não serão alterados, entre outros:

      appBar: AppBar(
        title: const Text("FlutterBrasil"),
      ),

Então, quando você chamar o setState(), não irá reconstrui-lo.

Criando outro Widget

Mas há também outra alternativa, criando outro componente.

Criaremos outra classe Stateful chamada SetStateComponent() onde iremos colocar somente o conteúdo que queremos que seja atualizado:

class SetStateComponent extends StatefulWidget {
  @override
  _MySetStateComponent createState() => _MySetStateComponent();
}

class _MySetStateComponent extends State {
  String nome = "Flutter";
  @override
  Widget build(BuildContext context) {
    print('buildComponent');
    return  Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(nome),
            RaisedButton(
              onPressed: () {
                setState(() {
                  nome = "Brasil";
                });
              },
              child: Text("alterar nome"),
            )
          ],
    );
  }
}

Após, iremos modificar a nossa classe SetState() para Stateless e chamar a nova classe criada SetStateComponent():

class SetState extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('build');
    return Scaffold(
      appBar: AppBar(
        title: const Text("FlutterBrasil"),
      ),
      body: SetStateComponent(),
    );
  }
}

Desta forma, eu posso controlar os componentes que serão atualizados. 

Código Completo:

Clique aqui e veja aqui este código em funcionamento.