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 is to add a parent ProviderScope
in our main()
function:
// inside main() runApp(ProviderScope( child: MyApp(), ));
Step 2 is to create a Provider<HiveDataStore>
:
// hive_data_store.dart final dataStoreProvider = Provider<HiveDataStore>((ref) { return HiveDataStore(); });
Step 3 is to use it in the HomePage
:
// 1. extend from ConsumerWidget class HomePage extends ConsumerWidget { // 2. Add an additional WidgetReference argument @override Widget build(BuildContext context, WidgetReference 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 WidgetReference
There are some similarities between the two:
- with Flutter we can use the
BuildContext
to access ancestor widgets such asNavigator
andMediaQuery
. - with Riverpod we can use this
WidgetReference
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
WidgetReference
to access any provider by reference.
Watch
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 providers such as StateNotifierProvider
, FutureProvider
or StreamProvider
. See my Essential Guide for more info.
4 comments