Um estudo sobre o Flutter FutureBuilder
Tags: flutter, widgets, google, mobile
Published: 2019-12-13 16:03:04

Esse artigo faz parte de uma série chamada "Widgets da Semana", para saber mais sobre essa ela leia nossa [introdução](https://dev.to/flutter/flutter-um-estudo-semanal-sobre-widgets-56g3).

## FutureBuilder
O [video](https://www.youtube.com/watch?v=ek8ZPdWj4Qo) do Widget da semana postado no dia 18 de setembro de 2018 fala sobre o FutureBuilder.

Quando falamos de arquitetura Web, requisições e etc é normal pensar em um cliente chamando um servidor. E nesse caminho mágico ocorrem uma série de coisas, mas o que importa para falarmos do FutureBuilder é: *sua requisição leva tempo!* 
Ela pode levar de alguns milissegundos a vários segundos pra te retornar algo importante - e esse retorno ainda por cima pode ser um erro! :D   

Pensando nisso, o FutureBuilder te permite lidar com esses percalços do mundo _assíncrono_ e dizer qual Widget deve ser renderizado de acordo com cada situação durante uma requisição. :O

Assim, você pode fazer o seguinte fluxo:
- Flutter, faça uma requisição pra https://minha-poke-api.com
- Enquanto você espera, mostre pro usuário uma _barra de loading_ 
- Se der bom, mostre uma _lista de pokemons_
- Se der ruim, mostre um _widget dizendo "não foi dessa vez, meu consagrado"_

E pra isso acontecer, você só precisa usar o _FutureBuilder_! Ele recebe, adivinha? Um _future_ e um _builder_.

```ruby
FutureBuilder(
  future: http.get('https://minha-poke-api.com'),
  builder: (context, snapshot) {
    return ...
  }
)
```

O _future_ recebe um processo assíncrono (não somente requisições) 
e o _builder_ recebe uma função que diz qual Widget deve ser construído.

Na função passada ao _builder_ temos um: 
 - _context_ que recebe um [BuildContext](https://api.flutter.dev/flutter/widgets/BuildContext-class.html) (Que merece um artigo próprio e não precisaremos ver por hora).
 - _snapshot_ do tipo [AsyncSnapshot](https://api.flutter.dev/flutter/widgets/AsyncSnapshot-class.html) (Esse sim nos ajuda e muito na hora de tratar essas requisições!!)


O _AsyncSnapshot_ possui propriedades que nos ajudam - E MUITO - a entender o que está acontecendo durante a requisição e tratar isso, por exemplo:
- Saber se ocorreu algum erro (_hasError_) ou se o retorno contém dados de fato (_hasData_)
- Saber o estado atual do processo assíncrono, se ele foi concluído (_done_), se ainda estamos aguardando um retorno (_waiting_), se temos de fato um processo (_active_) ou não (_none_). E por aí vai.

Sendo assim, podemos usar o _snapshot_ para tratar o fluxo que pretendemos fazer, por exemplo:

- Quando a requisição for concluída, verificar se ela teve algum erro
```ruby
  if (snapshot.hasError) {
    // Deu ruim :/ - Podemos pegar o snapshot.error
  } else {
    // Deu bom! :D - Podemos pegar o snapshot.data
  }
```

- Acompanhar o fluxo completo da requisição!!
```ruby
    switch (snapshot.connectionState) {
      case ConnectionState.none: 
        return Text('Aperte o botão para iniciar a requisição.');
      case ConnectionState.active: 
      case ConnectionState.waiting:
        return Text('Esperando requisição...');
      case ConnectionState.done:
        return Text('Uhul, acabou!');
    }
```

Agora sim, chega de enrolação! Prontos?
### Mãos à obra

FutureBuilder à postos
```ruby
FutureBuilder(
  future: ...,
  builder: (context, snapshot) {
    return ...
  }
)
```
Enquanto a requisição não for concluída, mostramos nossa barra de loading
```ruby
FutureBuilder(
  future: http.get('https://minha-poke-api.com'),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.done) {
      return ...
    } else {
      return CircularProgressIndicator();
    }
  }
)
```
Assim que ela for concluída, vamos verificar se não ocorreu nenhum erro, claro!
```ruby
FutureBuilder(
  future: http.get('https://minha-poke-api.com'),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.done) {
      if(snapshot.hasError) { 
        return OurErrorIndicator(snapshot.error);
      }     
      return ...
    } else {
      return CircularProgressIndicator();
    }
  }
)
```
E, finalmente: vamos montar nossos pokemons!
```ruby
FutureBuilder(
  future: http.get('https://minha-poke-api.com'),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.done) {
      if(snapshot.hasError) { 
        return OurErrorIndicator(snapshot.error);
      }     
      return PokeListGenegator(snapshot.data);
    } else {
      return CircularProgressIndicator();
    }
  }
)
```

Simples, prático e rápido. Esse é o FutureBuilder!

Alguns projetos e palestras estão prestes a sair do forno e agora você já deu um passo pra acompanhar isso com muito mais facilidade!

Se interessou? Cola com a [Flutter Nation](https://www.facebook.com/FlutterNationBr/): 

## Sobre Nós

Eu e o pessoal da Flutter Nation estamos em uma [página](https://www.facebook.com/FlutterNationBr/) e um [grupo](https://www.facebook.com/groups/FlutterNation/) no Facebook. 
Também estamos no [Meetup](https://www.meetup.com/pt-BR/FlutterNation/) e no [GitHub](https://github.com/Flutter-Nation)!