Saltar al contenido principal

Scoping providers

Scoping is the act of changing the behavior of a provider for only a small part of your application.

This is useful for:

  • Page/Widget-specific customization (e.g changing the theme of your app for one specific page)
  • Performance optimization (e.g rebuilding only the item that changes in a ListView)
  • Avoiding having to pass parameters around (such as for Family)

Scoping is achieved using Provider overrides, by overriding a provider in ProviderContainers/ProviderScopes that are not the root of your application.

caution

The scoping feature is highly complex and will likely be reworked in the future to be more ergonomic.

Thread carefully.

Defining a scoped provider

By default, Riverpod will not allow you to scope a provider. You need to opt-in to this feature by specifying dependencies on the provider.

The first scoped provider in your app will typically specify dependencies: [].
The following snippet defines a scoped provider that exposes the current item ID that is being displayed:

final currentItemIdProvider = Provider<String?>(
dependencies: const [],
(ref) => null,
);

Listening to a scoped provider

To listen to a scoped provider, use the provider as usual by obtaining Refs, (such as with Consumers).

final currentItemId = ref.watch(currentItemIdProvider);

If a provider is listening to a scoped provider, that scoped provider needs to be included in the dependencies of the provider that is listening to it:

final currentItemProvider = FutureProvider<Item?>(
dependencies: [currentItemIdProvider],
(ref) async {
final currentItemId = ref.watch(currentItemIdProvider);
if (currentItemId == null) return null;

// Fetch the item from a database or API
return fetchItem(id: currentItemId);
});
info

Inside dependencies, you only need to list scoped providers. You do not need to list providers that are not scoped.

Setting the value of a scoped provider

To set a scoped provider, you can use Provider overrides. A typical example is to specify overrides on ProviderScope like so:

class HomePage extends StatelessWidget {
const HomePage({super.key});


Widget build(BuildContext context) {
return ProviderScope(
overrides: [
currentItemIdProvider.overrideWithValue('123'),
],
// The detail page will rely on '123' as the current item ID, without
// having to pass it explicitly.
child: const DetailPageView(),
);
}
}