How to use Provider, Consumer, and ConsumerWidget

Notes

Up until now, we've been creating two instances of the HiveDataStore: one in the main.dart file and one inside the HomePage.

HiveDataStore is a dependency for the HomePage, and we should only create it once. We can do this by using Riverpod as a dependency injection solution.

Step 1: add a parent ProviderScope in our main() function:

Future<void> main() async {
  ...
  runApp(ProviderScope(
    child: MyApp(),
  ));
}

Step 2: create a Provider<HiveDataStore>:

// hive_data_store.dart
final dataStoreProvider = Provider<HiveDataStore>((ref) {
  return HiveDataStore();
});

Step 3: use it in the HomePage, which is now a ConsumerWidget:

// 1. extend from ConsumerWidget
class HomePage extends ConsumerWidget {
  // 2. Add an additional WidgetRef argument
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 3. get the dataStore with ref.watch()
    final dataStore = ref.watch(dataStoreProvider);
    return ValueListenableBuilder(
      valueListenable: dataStore.tasksListenable(),
      builder: (_, Box<Task> box, __) => TasksGridPage(
        tasks: box.values.toList(),
      ),
    );
  }
}

As an alternative to ConsumerWidget, we can return a Consumer inside the build() method, but this results in more boilerplate code.

BuildContext vs WidgetRef

There are some similarities between the two:

  • with Flutter we can use the BuildContext to access ancestor widgets such as Navigator and MediaQuery.
  • with Riverpod, we can use this WidgetRef to access all the providers that we have created.

And some differences:

  • BuildContext works inside the widget tree, and we can only use it to access ancestor widgets.
  • Riverpod providers are defined in the global scope and live outside the widget tree. We can use WidgetRef to access any provider by reference.

Watching a provider

Also note that calling ref.watch inside a widget will cause it to rebuild every time the Provider's value changes.

This is useful when we use providers such as StateNotifierProviderFutureProvider or StreamProvider. Read my Riverpod Ultimate Guide for more info.

Resources


Complete and Continue  
Discussion

4 comments