110

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 when we want access to the data, but you don't need the UI to change. So the following (taken from the docs) gets access to the data and updates the UI on new events:

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:

  1. Is this the correct way to distinguish Provider.of<X> and Consumer<X>. Former doesn't update UI, latter does?
  2. If listen isn't set to false will the widget be rebuilt by default or not rebuilt? What if listen is set to true?
  3. Why have Provider.of with the option to rebuild the UI at all when we have Consumer?
creativecreatorormaybenot
  • 114,516
  • 58
  • 291
  • 402
Oprimus
  • 1,652
  • 3
  • 11
  • 20
  • 4
    I'm just adding to this: context.watch() is another way to access data from a provider, this^ line is equivalent to: Provider.of(context) while context.read() is another way to access data from a provider, this^ line is equivalent to: Provider.of(context, listen: false) – Cedric May 02 '22 at 21:10
  • 2
    The fact that there are at least three different APIs for this same functionality: Provider.of context.watch and Consumer, not to mention ValueListenable and the rest, makes for a lot to wrap one's head around. I sympathize with the OP. What saved me is the "Your First Flutter App" codelab, that teaches this with context.watch. I found it very helpful. – Chris Nadovich Mar 30 '23 at 13:44

8 Answers8

127

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
Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
  • 2
    This is helpful. I'm going to accept this response, especially for others. But can you point to a reference for this statement: "Provider.of is the only way to obtain and listen to an object. Consumer, Selector, and all the *ProxyProvider calls Provider.of to work." This isn't something I've seen in the docs and it really helped me! – Oprimus Nov 09 '19 at 03:21
  • 14
    This is just an implementation detail of how Consumer/... works. Here's the [source](https://github.com/rrousselGit/provider/blob/master/packages/provider/lib/src/consumer.dart). You can see that `Consumer` is basically nothing but `Provider.of` in a new widget – Rémi Rousselet Nov 09 '19 at 04:07
  • 2
    Are there any resources about learning to prevent BuildContext misuse? – 吳強福 Mar 04 '20 at 09:19
  • 8
    @RémiRousselet link doesn't work anymore. Working link is: [source](https://github.com/rrousselGit/provider/blob/master/lib/src/consumer.dart) – iko May 24 '20 at 13:17
  • In a word; `Comsumer` uses `Provider.of` in fact but it has a builder which rebuild it's child widget. – Zia Feb 26 '22 at 02:48
  • what about ```context.watch``` & ```context.read``` ?? – Panagiss May 28 '22 at 15:00
  • @Panagiss - see the comment in under the original question by @Cedric - it explains `context.watch` and `context.read` https://stackoverflow.com/questions/58774301/when-to-use-provider-ofx-vs-consumerx-in-flutter#comment127381229_58774301 – muya_ Jul 23 '22 at 05:58
30

Provider.of<>

applying provider, whole widget will rebuild if listen true.

Consumer<>

using consumer only specifically allowed widget will rebuild.

Mijanur Rahman
  • 1,094
  • 1
  • 11
  • 20
17

For your questions:

  1. Is this the correct way to distinguish Provider.of<X> and Consumer<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.

  1. If listen isn't set to false will the widget be rebuilt by default or not rebuilt? What if listen is set to true?

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}).

  1. Why have Provider.of with the option to rebuild the UI at all when we have Consumer?

Pretty much covered by Rémi Rousselet's answer.

Lee Chee Kiam
  • 11,450
  • 10
  • 65
  • 87
14

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.

Jitesh Mohite
  • 31,138
  • 12
  • 157
  • 147
7

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/

Sachin
  • 1,206
  • 12
  • 13
6

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(context) you can get access to the variable you want to monitor and make changes in it.

Provider.of(context) with and without listen gives you a reference to the above-declared Provider object and a widget tree where it can be accessed from. But as said by others, it rebuild the whole widget tree it sits on top of when listen is not false.

In the end, you can use consumer to monitor any changes that happened using the above step

The consumer acts like a more granular listener and be applied to a fixed widget to help avoid unnecessary rebuilds.

grena
  • 1,011
  • 1
  • 10
  • 25
Saurabh Kumar
  • 2,088
  • 14
  • 17
2

it's just a personal preference and depends on how you understand and use provider. so the way i think of provider is it's just an object that is providing a ChangeNotifier Object that has Code and Data down the widget Tree.

So,I use :

Consumer<T>

When i want to listen to changes in Data and update/rebuild my UI according to those changes.

Provider.of<T>

When i just want to call the Code. with the listen parameter set to false.

Tarik Waleed
  • 97
  • 1
  • 8
0

if your problem is to know what the difference is, here is a track

Consumer

reload consumer-only child widgets

Provider.of (with listen true)

reload from the last buildcontext found in the tree

actually in a simple example

exemple1 provider.of

in exemple1 when I click on my container, his increase his size ( gesturedetector send a newvalue at h variable , h variable is in function named method in provider)

with 'provider.of' flutter rebuild at the first Buildcontext below @override

that mean the totality of tree are rebuild

exemple2 consumer

in exemple2 when I click on my container, his increase his size ( gesturedetector send a newvalue at h variable , h variable is in function named method in provider)but with consumer only sélectionned widget are rebuild

that mean one widget are rebuild the other widget doesn't "move"

I hope I could help you