在 Flutter 中何时使用 Provider.of < X > vs. Consumer < X >

我仍然对状态管理技术感到困惑,对于什么时候使用 Provider.of<X>和为什么使用 Consumer<X>感到有点困惑。我从 文件中了解到(我认为)在这两者之间进行选择时,当我们希望访问数据时,可以使用 Provider.of,但不需要更改 UI。因此,以下内容(取自文档)可以访问数据并在新事件上更新 UI:

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}');
},
),
),
);

然而,如果我们只需要数据,而不想用 UI 重新构建,我们会使用 Provider.of<X>,将 listen参数设置为 false,如下所示:

Provider.of<CartModel>(context, listen: false).add(item); \\Widget won't rebuild

但是,listen不是必需的,因此下面的代码也将运行:

Provider.of<CartModel>(context).add(item); \\listener optional

这让我想到几个问题:

  1. 这是区分 Provider.of<X>Consumer<X>的正确方法吗? 前者不更新 UI,后者更新 UI?
  2. 如果 listen没有设置为 false,那么小部件是默认重新构建还是不重新构建?如果 listen设置为 true怎么办?
  3. 当我们有 Consumer的时候,为什么还要选择 Provider.of来重建 UI 呢?
46280 次浏览

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

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.

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/

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.

Provider.of<>

applying provider, whole widget will rebuild if listen true.

Consumer<>

using consumer only specifically allowed widget will rebuild.

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.

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.