website/docs/concepts2/family.mdx
import { Link } from "/src/components/Link"; import { AutoSnippet, } from "/src/components/CodeSnippet"; import functionalFamily from './family/functional'; import notifierFamily from './family/notifier'; import singleOverride from 'raw-loader!./family/single_override.dart'; import allOverride from 'raw-loader!./family/all_overrides.dart';
One of Riverpod's most powerful feature is called "Families".
In short, it allows a provider to be associated with multiple independent states,
based on a unique parameter combination.
A typical use-case is to fetch data from a remote API, where the response depends on some parameters (such as a user ID or a search query or a page number). It enables defining a single provider that can be used to fetch and cache any possible parameter combination.
:::info If normal providers can be assimilated to a variable, then "family" providers can be assimilated to a Map. :::
Defining a family is done by slightly modifying the provider definition to receive a parameter.
For functional providers, the syntax is as follows:
<AutoSnippet {...functionalFamily} />
And for notifier providers, the syntax is:
<AutoSnippet {...notifierFamily} />
:::info Although not strictly required, it is highly advised to enable <Link documentID="concepts2/auto_dispose" /> when using families.
This avoids memory leaks in case the parameter changes and the previous state is no longer needed. :::
Providers that receive parameters see their usage slightly modified too.
Long story short, you need to pass the parameters that your provider expects, as follows:
final user = ref.watch(userProvider('123'));
:::caution
Parameters passed need to have a consistent ==/hashCode.
View "family" as a Map, where the parameters are the key and the provider's state is the value.
As such, if the ==/hashCode of a parameter changes, the value
obtained will be different.
Therefore code such as the following is incorrect:
// Incorrect parameter, as `[1, 2, 3] != [1, 2, 3]`
ref.watch(myProvider([1, 2, 3]));
To help spot this mistake, it is recommended to use the riverpod_lint and enable the provider_parameters lint rule. Then, the previous snippet would show a warning. See <Link documentID="introduction/getting_started" hash="enabling-riverpod_lintcustom_lint" /> for installation steps. :::
You can read as many "family" providers as you want, and they will all be independent. As such, it is legal to do:
class Example extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final user1 = ref.watch(userProvider('123'));
final user2 = ref.watch(userProvider('456'));
// user1 and user2 are independent.
}
}
When trying to mock a provider in tests, you may want to override a family provider.
In that scenario, you have two options: