When to use Provider.of<X> vs. Consumer<X> in Flutter
FlutterDartFlutter ProviderFlutter Problem Overview
I'm still wrapping my head around state-management techniques in flutter and am a bit confused about when and why to use Provider.of<X>
vs. Consumer<X>
. I understand (I think) from the documentation that when choosing between these two you would use Provider.of
return HumongousWidget(
// ...
child: AnotherMonstrousWidget(// <- This widget will rebuild on new data events
// ...
child: Consumer<CartModel>(
builder: (context, cart, child) {
return Text('Total price: ${cart.totalPrice}');
},
),
),
);
Whereas, where we only need the data on don't want to rebuild with UI, we'd use Provider.of<X>
with the listen
parameter set to false
, as below:
Provider.of<CartModel>(context, listen: false).add(item); \\Widget won't rebuild
However, listen
isn't required and so the following will run too:
Provider.of<CartModel>(context).add(item); \\listener optional
So this brings me to a few questions:
- Is this the correct way to distinguish
Provider.of<X>
andConsumer<X>
. Former doesn't update UI, latter does? - If
listen
isn't set tofalse
will the widget be rebuilt by default or not rebuilt? What iflisten
is set totrue
? - Why have
Provider.of
with the option to rebuild the UI at all when we haveConsumer
?
Flutter Solutions
Solution 1 - Flutter
It doesn't matter. But to explain things rapidly:
Provider.of
is the only way to obtain and listen to an object.
Consumer
, Selector
, and all the *ProxyProvider calls Provider.of
to work.
Provider.of
vs Consumer
is a matter of personal preference. But there's a few arguments for both
Provider.of
- can be called in all the widgets lifecycle, including click handlers and
didChangeDependencies
- doesn't increase the indentation
Consumer
- allows more granular widgets rebuilds
- solves most BuildContext misuse
Solution 2 - Flutter
Provider.of<>
applying provider, whole widget will rebuild if listen true.
Consumer<>
using consumer only specifically allowed widget will rebuild.
Solution 3 - Flutter
For your questions:
- Is this the correct way to distinguish
Provider.of<X>
andConsumer<X>
. Former doesn't update UI, latter does?
Provider.of<X>
depends on value of listen
to trigger a new State.build
to widgets and State.didChangeDependencies
for StatefulWidget
.
Consumer<X>
always update UI, as it uses Provider.of<T>(context)
, where listen
is true
. See full source here.
- If
listen
isn't set tofalse
will the widget be rebuilt by default or not rebuilt? What iflisten
is set totrue
?
Default value is true
, means will trigger a new State.build
to widgets and State.didChangeDependencies
for StatefulWidget
. See full source here.
static T of<T>(BuildContext context, {bool listen = true})
.
- Why have
Provider.of
with the option to rebuild the UI at all when we haveConsumer
?
Pretty much covered by Rémi Rousselet's answer.
Solution 4 - Flutter
There should not be any performance concern by using it, moreover, we should use consumers if we want to change some specific widget only on screen. This is the best approach I can say in terms of coding practice.
return Container(
// ...
child: Consumer<PersonModel>(
builder: (context, person, child) {
return Text('Name: ${person.name}');
},
),
);
Like in the above example, we are only required to update the value of the Single Text Widget so add consumers there instead of Provider which is accessible to other widgets as well.
Note: Consumer or Provider update the only reference of your instance which widgets are using, if some widgets are not using then it will not re-drawn.
Solution 5 - Flutter
The widget Consumer
doesn't do any fancy work. It just calls Provider.of
in a new widget, and delegate its build implementation to [builder].
It's just syntactic sugar for Provider.of
but the funny thing is I think Provider.of
is simpler to use.
Look at this article for more clearance https://blog.codemagic.io/flutter-tutorial-provider/
Solution 6 - Flutter
We have 3 things to understand here.
> When you wrap Provider around a widget it sets up a reference to a widget tree and a variable whose changes you want to refer to.
using Provider.of