ChangeNotifierProvider 与 ChangeNotifierProvider.value

ChangeNotifierProvider vs ChangeNotifierProvider.value

我对这个框架还很陌生,我在使用提供程序包进行状态管理时遇到了 ChangeNotifierProviderChangeNotifierProvider.value,但我无法区分它们的用例。

我曾使用 ChangeNotifierProvider 代替 ChangeNotifierProvider.value,但它没有按预期工作。

官方文档有帮助吗?

DO use ChangeNotifierProvider.value to provider an existing ChangeNotifier:

ChangeNotifierProvider.value(
  value: variable,
  child: ...
)

DON'T reuse an existing ChangeNotifier using the default constructor.

ChangeNotifierProvider(
  builder: (_) => variable,   
  child: ... 
)

另请查看作者关于此的Github issue

ValueNotifier 和 ChangeNotifier 密切相关。

In fact, ValueNotifier is a subclass of ChangeNotifier that implements ValueListenable.

这是Flutter SDK中ValueNotifier的实现:

/// A [ChangeNotifier] that holds a single value.
///
/// When [value] is replaced with something that is not equal to the old
/// value as evaluated by the equality operator ==, this class notifies its
/// listeners.
class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> {
  /// Creates a [ChangeNotifier] that wraps this value.
  ValueNotifier(this._value);

  /// The current value stored in this notifier.
  ///
  /// When the value is replaced with something that is not equal to the old
  /// value as evaluated by the equality operator ==, this class notifies its
  /// listeners.
  @override
  T get value => _value;
  T _value;
  set value(T newValue) {
    if (_value == newValue)
      return;
    _value = newValue;
    notifyListeners();
  }

  @override
  String toString() => '${describeIdentity(this)}($value)';
}

那么,我们什么时候应该使用 ValueNotifier 和 ChangeNotifier?

Use ValueNotifier if you need widgets to rebuild when a simple value changes. Use ChangeNotifier if you want more control on when notifyListeners() is called.

是ChangeNotifierProvider.value与create函数的重要区别。当您在单个列表或网格项目中使用 Provider 时,Flatter 会在项目离开屏幕时删除项目,并在项目重新进入屏幕时重新添加它们,在这种情况下,实际发生的是小部件本身被 Flutter 重用,而只是数据附加到它的更改。所以 Flatter 会回收同一个小部件,但不会破坏它 并重新创建它。当我们将 Provider 与 create 函数一起使用时。

ChangeNotifierProvider(
  create: (_) => new MyChangeNotifier(),
  child: ...
)

☝☝☝ 这里的内容会随着时间的推移而变化,我们的提供商不会接我们。

在单个列表或网格项中,我们应该使用 Provider 点值。

ChangeNotifierProvider.value(
  value: new MyChangeNotifier(),
  child: ...
)

让我们逐步进行。

什么是 ChangeNotifier?

扩展 ChangeNotifier 的 class 可以调用 notifyListeners() 任何时候 class 中的数据已更新并且您想让侦听器知道该更新。这通常在视图模型中完成,以通知 UI 根据新数据重建布局。

这是一个例子:

class MyChangeNotifier extends ChangeNotifier {
  int _counter = 0;
  int get counter => _counter;

  void increment() {
    _counter++;
    notifyListeners();
  }
}

我在 A beginner’s guide to architecting a Flutter app.

中写了更多相关内容

什么是 ChangeNotifierProvider?

ChangeNotifierProvidermany types of providers in the Provider package 之一。如果您已经有一个 ChangeNotifier class(如上面的那个),那么您可以使用 ChangeNotifierProvider 将它提供到 UI 布局中您需要它的地方。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<MyChangeNotifier>(        // define it
      create: (context) => MyChangeNotifier(),              // create it
      child: MaterialApp(
        ...

          child: Consumer<MyChangeNotifier>(                // get it
            builder: (context, myChangeNotifier, child) {
              ...
                  myChangeNotifier.increment();             // use it

请特别注意,在这一行中创建了 MyChangeNotifier class 的新实例:

create: (context) => MyChangeNotifier(),

这是在第一次构建小部件时完成的一次,而不是在后续重建时完成。

那么 ChangeNotifierProvider.value 是什么?

如果您已经创建了 ChangeNotifier class 的实例,请使用 ChangeNotifierProvider.value。如果您在 StatefulWidgetState class 的 initState() 方法中初始化了 ChangeNotifier class,则可能会发生这种情况。

在那种情况下,您不想创建 ChangeNotifier 的全新实例,因为您会浪费已经完成的任何初始化工作。使用 ChangeNotifierProvider.value 构造函数允许您提供预先创建的 ChangeNotifier 值。

class _MyWidgeState extends State<MyWidge> {

  MyChangeNotifier myChangeNotifier;

  @override
  void initState() {
    myChangeNotifier = MyChangeNotifier();
    myChangeNotifier.doSomeInitializationWork();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<MyChangeNotifier>.value(
      value: myChangeNotifier,                           // <-- important part
      child: ... 

特别注意这里没有create参数,而是value参数。这就是您传递 ChangeNotifier class 实例的地方。同样,不要尝试在那里创建新实例。

你也可以在官方文档中找到ChangeNotifierProviderChangeNotifierProvider.value的用法:https://pub.dev/packages/provider#exposing-a-value

基本上,带有 builder(Provider v3) 或 create(Provider v4) 参数的 ChangeNotifierProvider 是一个处理提供者,这个提供者拥有状态源并管理它的生命周期。值提供者仅引用状态源,但不管理其生命周期。 在配置提供者时,builder 或 create 参数提供了创建状态源的功能。在值提供者中有一个值参数,它引用状态源,您负责根据需要创建和处理状态源。