Flutter: Usando o Riverpod Future Provider para buscar API
As operações assíncronas estão em quase todos os aplicativos que funcionam com back-end. Quer seja GraphQL, Rest ou qualquer outra coisa, você tem o mesmo padrão. Você inicia a solicitação e espera até que ela seja concluída antes de mostrar os dados. No Flutter, Riverpod nos fornece o FutureProvider. Com o FutureProvider, a UI pode lidar com isso de forma síncrona. O FutureProvider informará aos Widgets quando os dados estiverem prontos ou quando a chamada falhou.
FutureProvider
Este provedor é de alguma forma uma combinação de Provider<T> e FutureBuilder, nesse sentido você pode criar um valor síncrono e observar alterações nele, como se ele fosse recuperado com sucesso.
Riverpod remove as redundâncias de usar algo como FutureBuilder e manipula automaticamente o código.
Como visto, _data é um tipo de AsyncValue<T> que fornece ao método when opções para data(), loading() e error() que podemos manipular conforme necessário.
Isso é muito mais fácil do que usar FutureBuilder ou StreamProvider. Incrível, certo?
Vamos começar. Explicarei o tratamento da API com uma solicitação get.
Vamos instalar os pacotes http e flutter_riverpod. Certifique-se de instalar a versão mais recente.
dependencies: http: ^0.13.6 flutter_riverpod: ^2.4.6
Instale o pacote. Execute o comando para obter o pacote.
Instale o pacote. Você pode salvar o arquivo pubspec.yaml
.
flutter pub get
Estrutura de pastas:
API:https://reqres.in/api/users?page=2
Estrutura de pastas: primeiro vamos começar criando a classe Model
user_model.dart
class UserModel { final int id; final String email; final String firstname; final String lastname; final String avatar; UserModel( {required this.id, required this.email, required this.firstname, required this.lastname, required this.avatar}); factory UserModel.fromJson(Map<String, dynamic> json) { return UserModel( id: json['id'], email: json['email'], firstname: json['first_name'] ?? 'First Name', lastname: json['last_name'] ?? 'Last Name', avatar: json['avatar'] ?? 'https://img.freepik.com/free-vector/illustration-user-avatar-icon_53876-5907.jpg?w=740'); } }
Em segundo lugar, criaremos uma classe de serviço API e definiremos o método para decodificar API com pacote Http
class ApiService { String endpoint = 'https://reqres.in/api/users?page=2'; Future<List<UserModel>> getUser() async { Response response = await get(Uri.parse(endpoint)); if (response.statusCode == 200) { final List result = jsonDecode(response.body)['data']; return result.map(((e) => UserModel.fromJson(e))).toList(); } else { throw Exception(response.reasonPhrase); } } } //Provedor de SERVIÇO API final apiProvider = Provider<ApiService>((ref) => ApiService());
Aqui usamos a referência Provider apiProvider normal APIService() inteira
Em terceiro lugar, acessamos a API via FutureProvider
Para acessar os dados da API, criamos um provedor do userDataProvider. Podemos acessar esta APIclass no FutureProvider. O FutureProvider retornará a lista de <UserModel>
que fornecemos pelo apiProvider.
final userDataProvider = FutureProvider<List<UserModel>>((ref) async { return ref.read(apiProvider).getUser(); });
Finalmente, vamos iniciar a IU
Primeiro, podemos criar um novo ConsumerWidget para usar a função ref.watch para recuperar os artigos. Então, podemos usar a função when no Future que recuperamos com o gancho. Com base no estado atual, podemos retornar o widget correto. Quando os artigos estiverem carregando, retornaremos o CircularProgressIndicator. Se os artigos estiverem prontos, podemos exibi-los com um simples ListView e ListTile.
class Homepage extends ConsumerWidget { const Homepage({Key? key}) : super(key: key); @override Widget build(BuildContext context, ref) { final _data = ref.watch(userDataProvider); return Scaffold( appBar: AppBar( title: const Text('User Profile'), ), body: _data.when( data: (_data) { return Column( children: [ ..._data.map((e) => ListView(shrinkWrap: true, children: [ InkWell( onTap: () => Navigator.of(context).push( MaterialPageRoute( builder: (context) => DetailPage( e: e, ), ), ), child: ListTile( title: Text(e.firstname), subtitle: Text(e.lastname), trailing: CircleAvatar( backgroundImage: NetworkImage(e.avatar), ), ), ), ])), ], ); }, error: (err, s) => Text(err.toString()), loading: () => const Center( child: CircularProgressIndicator(), ), ),); } }
Código Completo no Meu GitHub: (link)