在Flutter中,何时使用Provider.of<X>和Consumer<X>?

114
我正在学习Flutter中的状态管理技术,对于何时以及为什么使用Provider.of<X>Consumer<X>还有些困惑。根据文档,当我们想要访问数据但不需要更新UI时,应该使用Provider.of。因此,以下代码(摘自文档)可以访问数据并在新事件上更新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,而后者会吗?
  2. 如果未将listen设置为false,小部件是否会默认重建或不重建?如果将listen设置为true呢?
  3. 既然有了Consumer,为什么还要使用具有重建UI选项的Provider.of

4
我只是在补充一点:context.watch<CartModel>() 是从provider中访问数据的另一种方式,这一行与以下内容等价: Provider.of<CartModel>(context)而context.read<CartModel>() 是从provider中访问数据的另一种方式,这一行与以下内容等价: Provider.of<CartModel>(context, listen: false) - Cedric
2
至少有三种不同的API可用于实现相同的功能:Provider.of、context.watch和Consumer,更别提ValueListenable等等。这使得人们需要花费很多心思来理解它们。我能够理解原帖作者的感受。对我帮助很大的是“你的第一个Flutter应用”codelab,它使用了context.watch进行教学。我发现这非常有用。 - Chris Nadovich
8个回答

131

没关系。但是为了快速解释:

Provider.of 是获取并监听对象的唯一方式。 ConsumerSelector 和所有的*ProxyProvider调用都使用Provider.of来工作。

Provider.ofConsumer之间是个人偏好的问题。但是有一些支持双方的观点。

Provider.of

  • 可以在所有小部件的生命周期中调用,包括点击处理程序和didChangeDependencies
  • 不增加缩进

Consumer

  • 允许更精细的小部件重建
  • 解决了大多数BuildContext误用

2
这很有帮助。我会接受这个回答,特别是为了其他人。但是你能指出这个声明的参考资料吗:“Provider.of是获取和监听对象的唯一方法。Consumer、Selector和所有*ProxyProvider调用Provider.of来工作。”这不是我在文档中看到的内容,它真的帮了我很多! - Oprimus
14
这只是“Consumer/...”工作原理的一个实现细节。这是源代码。你可以看到,“Consumer”本质上就是在一个新小部件中使用Provider.of - Rémi Rousselet
2
有没有关于学习如何防止BuildContext滥用的资源? - 吳強福
8
@RémiRousselet的链接已经失效了。工作链接是:source - iko
简而言之,Comsumer 实际上使用了 Provider.of,但它有一个构建器来重建其子小部件。 - Zia
显示剩余2条评论

35

Provider.of<>

使用 Provider,如果 listen 为 true,则整个 widget 将被重建。

Consumer<>

使用 Consumer,只有特定允许的 widget 将被重建。


如果我们在消费者内使用provider.of listen true会怎样? - Qaiser Hussain

19

针对您的问题:

  1. 区分 Provider.of<X>Consumer<X> 的正确方式是什么?前者不更新UI,后者会更新吗?

Provider.of<X> 取决于 listen 值的变化来触发新的 State.build 以及 StatefulWidgetState.didChangeDependencies

Consumer<X> 总是更新UI,因为它使用了 Provider.of<T>(context),其中 listentrue。详见完整源代码 这里

  1. 如果将 listen 设置为 false,那么小部件是否会默认重建或不重建?如果将 listen 设置为 true,会怎样?

默认值为 true,意味着会触发新的 State.build 以及 StatefulWidgetState.didChangeDependencies。详见完整源代码 这里

static T of<T>(BuildContext context, {bool listen = true})

  1. 既然有了 Consumer,为什么还要提供重建UI的选项呢?

这个问题已经被 Rémi Rousselet 的 回答详细解答了。


15

使用它不应该有任何性能问题,此外,如果我们只想在屏幕上更改特定的小部件,我们应该使用消费者。从编码实践的角度来看,这是我能说的最佳方法。

 return Container(
    // ...
    child: Consumer<PersonModel>(
      builder: (context, person, child) {
        return Text('Name: ${person.name}');
      },
    ),
  );

就像上面的例子一样,我们只需要更新单个文本小部件的值,所以请将消费者添加到那里而不是提供者,因为后者对其他小部件也可访问。

注意:消费者或提供者仅更新使用您实例的小部件的引用,如果某些小部件未使用,则它不会重新绘制。


7
我们需要理解以下3个概念。
当您在小部件周围包装Provider时,它会设置一个对小部件树和想要引用其更改的变量的引用。
使用Provider.of(context)可以访问要监视并进行更改的变量。
有listen和没有listen的Provider.of(context)都会为您提供对上面声明的Provider对象和可以从中访问该对象的小部件树的引用。但是,如其他人所说,如果listen不为false,则会重建它所处的整个小部件树。
最后,可以使用consumer来监视上述步骤中发生的任何更改。
Consumer作为更精细的监听器,可应用于固定的小部件,以帮助避免不必要的重建。

7
Consumer小部件不会做任何花哨的工作。它只是在一个新的小部件中调用Provider.of,并将其构建实现委托给[builder]。 这只是Provider.of的语法糖,但有趣的是我认为Provider.of更简单易用。
点击此文章以获得更清晰的信息。

2

这只是个人偏好,取决于您如何理解和使用提供程序。

所以,我认为提供程序只是提供一个ChangeNotifier对象,该对象在小部件树中向下传递代码数据的对象。

因此,当我想要侦听数据的更改并根据这些更改更新/重建我的UI时,我使用:

Consumer<T>

Provider.of<T>

当我只想调用代码时,将监听参数设置为false。


0

如果你的问题是想知道区别在哪里,这里有一条线索

Consumer

重新加载仅限于消费者的子小部件

Provider.of(使用listen true)

从树中找到的最后一个BuildContext重新加载

实际上是一个简单的例子

exemple1 provider.of

在exemple1中,当我点击我的容器时,它会增加其大小(gesturedetector将新值发送到h变量,h变量在名为provider的方法中)

使用'provider.of',Flutter会在@override下的第一个BuildContext处重建

这意味着整个树都会被重建

exemple2 consumer

在exemple2中,当我点击我的容器时,它会增加其大小(gesturedetector将新值发送到h变量,h变量在名为provider的方法中),但只有选择的小部件才会被重新构建

这意味着一个小部件被重建,而另一个小部件不会“移动”

希望我能帮到你


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接