Riverpod — Gestion compilée des dépendances pour Flutter

Auteur : IT Sectr Publié le : 2026-02-19 Temps de lecture : 7 min

Riverpod — un gestionnaire d'état et de dépendances compilé pour Flutter, créé par Remi Rousselet en 2021 comme successeur de Provider. Riverpod résout les problèmes fondamentaux de Provider : absence de vérification à la compilation, dépendance à BuildContext et complexité avec ProviderNotFoundException. Selon pub.dev, le paquet a plus de 5 mille likes et remplace activement Provider dans les nouveaux projets.

Points clés

  • ProviderRef — un objet pour accéder à d'autres providers à l'intérieur d'un provider
  • AsyncValue — une enveloppe pour les données asynchrones avec les états loading/error/data
  • Notifier — une classe pour l'état mutable avec des méthodes de mutation
  • ProviderScope — le widget racine qui gère tous les providers
  • Code Generation — des annotations @riverpod pour la génération automatique de providers

Qu'est-ce que Riverpod ?

Riverpod est une bibliothèque de gestion d'état et d'injection de dépendances pour Flutter qui compile les descriptions de providers en code Dart sécurisé. Contrairement à Provider, les providers Riverpod ne sont pas liés à BuildContext : ils sont créés globalement ou dans ProviderScope et sont accessibles de n'importe où. Le compilateur vérifie les types, les dépendances et l'intégrité du graphe de providers à la compilation, éliminant les erreurs d'exécution comme ProviderNotFoundException.

Riverpod utilise le modèle override pour les tests : chaque provider peut être surchargé via ProviderScope.overrideWith sans créer de sous-classes ou simuler des interfaces. Cela rend les tests isolés : chaque test obtient sa propre copie du graphe de dépendances qui est entièrement contrôlée.

Selon le Flutter Community Survey 2025, Riverpod occupe la troisième place en popularité après Provider et BLoC. Cependant, Riverpod est le paquet qui croît le plus rapidement : +120% d'installations en 2024. Les principales raisons : sécurité à la compilation, absence de ProviderNotFoundException, support asynchrone intégré via AsyncValue.

Types de providers

Riverpod fournit 8 types de providers, chacun pour un scénario spécifique : Provider (constante/service), StateProvider (état primitif), StateNotifierProvider (logique complexe avec StateNotifier), ChangeNotifierProvider (pour migration depuis Provider), FutureProvider (données asynchrones, une fois), StreamProvider (flux réactif), NotifierProvider (nouvelle API, Flutter 3.10+) et AsyncNotifierProvider (Notifier asynchrone).

Dart
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
  return CounterNotifier();
});

class CounterNotifier extends StateNotifier<int> {
  CounterNotifier() : super(0);

  void increment() => state++;
  void decrement() => state--;
}

class CounterScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Text('$count');
  }
}

ProviderRef — un objet passé à chaque provider pour accéder à d'autres providers. ref.watch — abonnement aux changements, ref.read — lecture unique, ref.invalidate — réinitialisation du cache. ProviderRef remplace BuildContext de Provider : n'importe quel provider peut lire d'autres providers sans accès à l'arbre de widgets. Cela permet de construire un graphe de dépendances en dehors de la couche UI.

ProviderScope — le widget racine, obligatoire pour le fonctionnement de Riverpod. ProviderScope stocke tous les providers, gère leur cycle de vie et met en cache les valeurs. Sans ProviderScope, l'application plantera avec ProviderNotFoundException. ProviderScope peut être imbriqué — une portée imbriquée surcharge les providers parents, ce qui est utilisé pour les tests et l'isolation des fonctionnalités.

AsyncValue et travail avec l'asynchronie

AsyncValue — une classe scellée de Riverpod pour représenter l'état asynchrone. AsyncValue a trois variantes : AsyncData (données réussies), AsyncError (erreur), AsyncLoading (chargement). Au lieu de basculer manuellement entre loading/error/data, chaque FutureProvider ou StreamProvider retourne automatiquement AsyncValue, et le widget gère les trois états via ref.watch.

Dart
final userProvider = FutureProvider((ref) async {
  final api = ref.watch(apiProvider);
  return await api.fetchUser();
});

class UserScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final userAsync = ref.watch(userProvider);
    return userAsync.when(
      data: (user) => UserWidget(user),
      error: (e, _) => ErrorWidget(e.toString()),
      loading: () => CircularProgressIndicator(),
    );
  }
}

AsyncValue.when — une méthode pour le pattern-matching des trois états. Le compilateur vérifie que les trois cas sont traités — si vous oubliez loading ou error, le code ne compilera pas. AsyncValue.whenData — uniquement pour data (si loading/error ne sont pas nécessaires). AsyncValue.guard — une enveloppe autour de try-catch pour convertir les exceptions en AsyncError. keepAlive — un drapeau qui empêche la destruction du cache du provider lorsqu'il sort de la portée.

Génération de code et @riverpod

Génération de code — une fonctionnalité clé de Riverpod 2.0+. L'annotation @riverpod sur une fonction génère automatiquement un provider avec le type correct, le support du refactoring et l'autocomplétion. La génération de code utilise riverpod_generator et build_runner. Le développeur écrit une fonction pure, et tout le reste — types, classes, constructeurs factory — est généré automatiquement.

Dart
@riverpod
String helloWorld(HelloWorldRef ref) {
  return 'Hello World';
}

// Généré : final helloWorldProvider = Provider((ref) => 'Hello World');

@riverpod
class Counter extends _$Counter {
  int build() => 0;
  void increment() => state++;
}

Notifier — la nouvelle API pour l'état mutable avec génération de code. Notifier est une classe avec une méthode build() et des méthodes de mutation d'état. Contrairement à StateNotifier, Notifier ne nécessite pas de classe d'état séparée et fournit un accès direct à state via getter/setter. Riverpod génère automatiquement un NotifierProvider pour chaque classe Notifier annotée avec @riverpod.

build_runner : la génération de code est lancée avec la commande dart run build_runner build. Les fichiers générés ont le suffixe .g.dart et sont importés dans le code source. Lorsque les annotations ou les types de providers changent, la génération de code doit être relancée. Riverpod 2.x recommande la génération de code pour tous les nouveaux projets — la création manuelle de providers devient obsolète.

Riverpod vs Provider

Différences clés entre Riverpod et Provider : indépendance de BuildContext, sécurité à la compilation, support asynchrone intégré, mise en cache automatique et tests via override. Provider nécessite BuildContext pour accéder à l'état (context.watch, context.read), Riverpod utilise WidgetRef et des providers déclarés globalement.

CaractéristiqueProviderRiverpod
Dépendance à BuildContextOuiNon
Vérification à la compilationNonOui (via @riverpod)
ProviderNotFoundExceptionRuntimeImpossible
AsynchronieManuelleAsyncValue (intégré)
TestsEnveloppe dans ProviderProviderScope.overrideWith
Mise en cacheNonAutomatique + keepAlive

Migration depuis Provider : Riverpod prend en charge ChangeNotifierProvider.adaptive pour utiliser les ChangeNotifier existants sans réécriture. Migration progressive : d'abord les nouvelles fonctionnalités sont écrites avec Riverpod, puis les anciennes instances Provider sont remplacées par des providers Riverpod via un adaptateur. Les deux paquets peuvent coexister dans un projet, permettant de migrer sans geler le développement.

Tester Riverpod

Tester Riverpod est basé sur ProviderScope.overrideWith. Chaque provider est surchargé à l'intérieur d'un ProviderScope de test sans mocks ni conteneurs DI. ProviderContainer — un environnement isolé pour les tests sans Flutter (Dart pur), permettant de tester les providers sans rendu de widgets.

Dart
import 'package:flutter_test/flutter_test.dart';
import 'package:riverpod/riverpod.dart';

void main() {
  test('Counter increments correctly', () {
    final container = ProviderContainer();
    container.read(counterProvider.notifier).increment();
    expect(container.read(counterProvider), 1);
  });

  testWidgets('UI updates on increment', (tester) async {
    await tester.pumpWidget(
      ProviderScope(
        overrides: [counterProvider.overrideWithValue(5)],
        child: CounterScreen(),
      ),
    );
    expect(find.text('5'), findsOneWidget);
  });
}

ProviderContainer — sans Flutter. Utilisez ProviderContainer pour les tests unitaires de providers sans widgets. overrideWithValue — remplacer un provider par une valeur spécifique. overrideWith — remplacer par une fabrique de providers (pour simuler des services). autodispose — dans les tests, vérifiez que le provider est détruit lorsqu'il sort de la portée en utilisant container.dispose().

Questions fréquentes

En quoi Riverpod est-il différent de BLoC ?

Riverpod est une bibliothèque de gestion d'état avec des providers globaux, AsyncValue et génération de code. BLoC est un modèle architectural avec Event → Stream → State. Riverpod est plus facile à apprendre et offre une meilleure DX grâce aux annotations @riverpod. BLoC fournit un isolement strict de la logique métier et un traçage des événements via BlocObserver. Le choix dépend du paradigme du projet : Riverpod est plus proche de Provider, BLoC — des flux réactifs.

Qu'est-ce que autodispose dans Riverpod ?

Autodispose est un mécanisme de destruction automatique d'un provider lorsque personne n'y est abonné. Par défaut, tous les providers Riverpod font autodispose : lorsqu'un widget quitte l'arbre, le provider est supprimé de la mémoire. keepAlive — un drapeau qui désactive autodispose pour les providers qui doivent toujours vivre (clients API, référentiels, paramètres). Cela évite les fuites de mémoire — les providers inutilisés sont automatiquement détruits.

Comment fonctionne ref.invalidate ?

ref.invalidate — une méthode qui réinitialise de force le cache du provider. Après invalidate, le provider est recréé à la prochaine lecture : FutureProvider réexécute la fonction asynchrone, StreamProvider se réabonne au flux. Utilisez invalidate pour forcer l'actualisation des données (pull-to-refresh, changement d'utilisateur). ref.refresh — une combinaison d'invalidate + lecture : réinitialise et lit immédiatement la nouvelle valeur en une seule opération.

Peut-on utiliser Riverpod sans génération de code ?

Oui. Riverpod 1.x fonctionne uniquement sans génération de code — les providers sont créés manuellement avec Provider(), StateNotifierProvider(), FutureProvider(), etc. Riverpod 2.x prend en charge les deux approches. Sans génération de code, il y a plus de code répétitif mais aucune dépendance à build_runner et dart run build_runner build. Pour les petits projets (jusqu'à 30 providers), la création manuelle est justifiée ; pour les grands, la génération de code est obligatoire.

Que sont les providers Family ?

Family — un modificateur de provider qui accepte un paramètre externe. Par exemple, userProvider(123) — un provider qui charge un utilisateur avec l'ID 123. Les providers Family mettent en cache le résultat pour chaque paramètre unique séparément. Utilisez Family pour les listes d'éléments où chaque élément est chargé par ID. Le modificateur Family est disponible pour tous les types de providers : Provider.family, FutureProvider.family, StreamProvider.family.

Résumé

  • Riverpod — un gestionnaire d'état compilé, successeur de Provider sans ProviderNotFoundException
  • ProviderRef — un remplacement de BuildContext pour accéder aux providers dans d'autres providers
  • AsyncValue — une classe scellée avec les états loading/error/data pour les données asynchrones
  • Génération de code @riverpod — inférence automatique de types et fabriques de providers
  • ProviderScope.overrideWith — tests isolés sans mocks ni conteneurs DI
  • Family — providers paramétrés avec mise en cache individuelle
  • autodispose et keepAlive — gestion automatique du cycle de vie des providers

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi