在新小部件中使用提供程序实例时哪个更好?

Which is better when using provider instance in a new widget?

假设我编写了如下代码。 我有一个名为 SampleProvider 的提供程序,我在我的主要小部件中使用它。

class SampleProvider extends ChangeNotifier {}

class MainWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    SampleProvider provider = Provider.of<SampleProvider>(context);
  }
}

然后,我想制作一个新的小部件并在新的小部件中使用此提供程序。 会有两个选择。 首先,我只是在新的小部件中实例化另一个提供者,如下所示。

class NewWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    SampleProvider provider = Provider.of<SampleProvider>(context);
  }
}

或者,我可以将它作为构造函数参数从主小部件发送到新小部件。 像这样:

class NewWidget extends StatelessWidget {
  final SampleProvider provider;
  NewWidget(this.provider);

  @override
  Widget build(BuildContext context) {
  }
}

我想第一个选项更好,因为 flutter 会根据其构建上下文绘制一个小部件,但我不确定。 我用谷歌搜索了很长时间,但没有成功。 谁能告诉我我是对还是错?还是他们没有区别?

是的,我认为第一个选项是更好的方法,在我的脑海中,我想不出在任何情况下您更喜欢第二个选项而不是第一个选项。

如果您不使用新的小部件作为任何其他小部件的子项,首选更好。 否则,第二个更好。

取决于偏好,不像第一个或第二个。

在initState中获取Provider时出现异常。我能做什么? 发生此异常是因为您正在尝试从永远不会再次调用的生命周期中收听提供者。

这意味着您要么应该使用另一个生命周期(构建),要么明确指定您不关心更新。

因此,而不是:

initState() {
  super.initState();
  print(context.watch<Foo>().value);
}

你可以做到:

Value value;

Widget build(BuildContext context) {
  final value = context.watch<Foo>.value;
  if (value != this.value) {
    this.value = value;
    print(value);
  }
}

它会在值发生变化时打印值(并且仅在它发生变化时)。

或者,您可以这样做:

initState() {
  super.initState();
  print(context.read<Foo>().value);
}

SRC:https://github.com/rrousselGit/provider#i-have-an-exception-when-obtaining-providers-inside-initstate-what-can-i-do

首选第一种方案,更容易重构。

假设您需要在您的小部件树中移动NewWidget,如果您选择第二种解决方案,则还需要修改“参数传递”代码,而第一种解决方案则不需要。

Provider pacakage的目的之一是顺便避免在widget树深处传递参数。