The Riverpod documentation clearly states that:
The watch method should not be called asynchronously, like inside an onPressed of an ElevatedButton. Nor should it be used inside initState and other State life-cycles.
In those cases, consider using ref.read instead.
You might be tempted to use ref.read to optimize the performance of a widget by doing: #
For example instead of:
@riverpod
class Counter extends _$Counter {
@override
int build() => 0;
void increment() => state = state + 1;
}
Widget build(BuildContext context, WidgetRef ref) {
// use "read" to ignore updates on a provider
final counter = ref.read(counterProvider.notifier);
return ElevatedButton(
onPressed: counter.increment,
child: const Text('button'),
);
}
we could do:
@riverpod
class Counter extends _$Counter {
@override
int build() => 0;
void increment() => state = state + 1;
}
Widget build(BuildContext context, WidgetRef ref) {
Counter counter = ref.watch(counterProvider.notifier);
return ElevatedButton(
onPressed: () => counter.increment(),
child: const Text('button'),
);
}
Both snippets achieve the same effect: our button will not rebuild when the counter increments.
On the other hand, the second approach supports cases where the counter is reset.
The documentation confuses me with using or not using ref.watch() inside onPressed.
There are a few more things I needed answers for:
- The docs advise avoiding read method inside build method means immediately inside build method before return statement, or everywhere?
- If watch method must not be used inside onPressed but helps in cases when providers are reset, how and when should I use them as
onPressed:() => ref.read(myProvider.notifier).myMethod()
vsref.watch(myProvider.notifier).myMethod()
- Is the advice to avoid watch method for async calls like in onPressed is for both providers
ref.watch(myProvider)
and notifiersref.watch(myProvider.notifier)
or any one? - As of my limited knowledge, watching notifiers do not cause rebuilds and must be safe to use anywhere for calling provider methods. Do I know right?
- What difference does it make to access provider methods from inside functions like
onPressed: () => ref.watch|read(myProvider.notifier).myMethod()
i.e every time accessing through ref, or using a variable like in above code examples:
// inside build
var notif = ref.read|watch(myProvider.notifier);
// somewhere inside return statement in a button's onPressed:
{
notif.myMethod();
}
Which approach must be preferred in which cases? And if latter method is more prone to unexpected outcomes based on the differences, How?