【问题标题】:ChangeNotifierProvider vs ChangeNotifierProvider.valueChangeNotifierProvider 与 ChangeNotifierProvider.value
【发布时间】:2019-12-11 15:25:06
【问题描述】:

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

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

【问题讨论】:

    标签: flutter frameworks provider state-management


    【解决方案1】:

    让我们分步进行。

    什么是 ChangeNotifier?

    扩展ChangeNotifier 的类可以调用notifyListeners(),只要该类中的数据已更新并且您想让侦听器知道该更新。这通常在视图模型中完成,以通知 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?

    ChangeNotifierProviderProvider package 中的many types of providers 之一。如果您已经有一个 ChangeNotifier 类(如上面的类),那么您可以使用 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 类的一个新实例是在这一行中创建的:

    create: (context) => MyChangeNotifier(),
    

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

    那么 ChangeNotifierProvider.value 是什么?

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

    在这种情况下,您不希望创建 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 类实例的地方。同样,不要尝试在那里创建新实例。

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

    【讨论】:

    • 我希望 stackoverflow 上的所有答案都和这个一样好。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

      ☝☝☝这里是内容随时间变化,我们的供应商不会接我们。

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

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

      【讨论】:

        【解决方案4】:

        ValueNotifier 和 ChangeNotifier 密切相关。

        实际上,ValueNotifier 是 ChangeNotifier 的子类,它实现 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?

        如果您需要小部件在简单值时重建,请使用 ValueNotifier 变化。如果您想更多地控制何时使用 ChangeNotifier notifyListeners() 被调用。

        【讨论】:

        • 一个离题的答案,虽然。
        【解决方案5】:

        官方文档有帮助吗?

        使用 ChangeNotifierProvider.value 来提供现有的ChangeNotifier

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

        不要使用默认构造函数重用现有的ChangeNotifier

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

        还可以从作者那里查看Github issue

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-06-06
          • 1970-01-01
          • 2021-11-14
          • 2021-11-15
          • 1970-01-01
          • 2021-12-10
          • 2020-07-16
          • 1970-01-01
          相关资源
          最近更新 更多