Como usar o RiverPod no Flutter

Tempo de leitura: 3 minutes
  • É semelhante ao Provider e é seguro para compilação e testável.
  • O Riverpod é inspirado no Provider, mas resolve alguns de seus principais problemas, como oferecer suporte a vários provedores do mesmo tipo; aguardando provedores assíncronos; adicionando provedores de qualquer lugar.
  • Não há mais necessidade de pular entre seu main.dart e seus arquivos de interface do usuário.
  • Coloque o código do seu estado compartilhado onde ele pertence, seja em um pacote separado ou ao lado do Widget que precisa dele, sem perder a testabilidade.

Os provedores são a parte mais importante de um aplicativo Riverpod. Um provedor é um objeto que encapsula um pedaço de estado e permite ouvir esse estado.

enum Status {
  initial,
  loading,
  success,
}

class RiverpodProvider extends StateNotifier<Status> {
  RiverpodProvider() : super(Status.initial);

  Future<void> fetchData() async {
    state = Status.loading;
    await Future.delayed(const Duration(seconds: 2));
    state = Status.success;
  }
}


final riverpodProvider =
    StateNotifierProvider.autoDispose((ref) => RiverpodProvider());

Na IU temos:

class RiverpodPage extends StatelessWidget {
  static const route = 'riverpod-page';

  const RiverpodPage({super.key});

  @override
  Widget build(BuildContext context) {
    return const ProviderScope(
      child: HomeRiverpod(),
    );
  }
}

Para que os widgets possam ler os provedores, precisamos agrupar o aplicativo inteiro em um widget “ProviderScope”. É aqui que o estado de nossos provedores será armazenado.

class HomeRiverpod extends ConsumerWidget {
  const HomeRiverpod({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final data = ref.read(riverpodProvider.notifier);

    return Scaffold(
      appBar: AppBar(title: const Text('Riverpod Page')),
      //É uma boa prática colocar seus widgets de consumidor o mais fundo possível na árvore.
      //Você não deseja reconstruir grandes porções da interface do usuário apenas porque algum detalhe em algum lugar foi alterado.
      body: Consumer(
        builder: (context, ref, child) {
          final state = ref.watch(riverpodProvider);
          if (state == Status.initial) {
            return const Center(child: Text('Press the Button'));
          }
          if (state == Status.loading) {
            return const Center(child: CircularProgressIndicator());
          }
          if (state == Status.success) {
            return const Center(child: Text('Success'));
          }
          return Container();
        },
      ),
      floatingActionButton: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          FloatingActionButton(
            child: const Icon(Icons.play_arrow),
            onPressed: () => data.fetchData(),
          ),
        ],
      ),
    );
  }
}

 

Usando ref para interagir com provedores

Existem três usos principais para “ref”:

  • Obter o valor de um provedor e ouvir as alterações, de modo que, quando esse valor mudar, isso reconstruirá o widget ou provedor que assinou o valor. Isso é feito usando ref.watch
  • Adicionar um ouvinte em um provedor para executar uma ação, como navegar para uma nova página ou mostrar um modal sempre que esse provedor for alterado.
    Isso é feito usando ref.listen.
  • Obter o valor de um provedor ignorando as alterações. Isso é útil quando precisamos do valor de um provedor em um evento como “on click”. Isso é feito usando ref.read.

E o resultado é o seguinte:

 

Prós

  • Riverpod é estável e mantido ativamente.
  • O Riverpod não depende diretamente da árvore de widgets. Os provedores são declarados globalmente e podem ser usados em qualquer lugar do aplicativo
  • Escreva código testável e mantenha a lógica fora da árvore de widgets

Contras

  • O Riverpod oferece muita liberdade para implementar o estado em seu aplicativo. isso pode ser um desafio para novos desenvolvedores escolherem a melhor abordagem.
  • Ele encoraja um antipadrão ruim de espalhar o estado compartilhado por toda a sua árvore de widgets. Isso pode tornar o código muito difícil de encontrar (não centralizado) e dificultar a depuração, pois há cadeias de dependência excessivas e acoplamentos entre provedores.