Flutter Provider:拆分通知的正确方法

Posted

技术标签:

【中文标题】Flutter Provider:拆分通知的正确方法【英文标题】:Flutter Provider: proper way to split notifying 【发布时间】:2021-01-04 20:34:51 【问题描述】:

我正在尝试使用Provider 拆分小部件的触发更新。 我正在使用最新的Flutter 版本。在应用程序中,我还使用context.select()context.watch()context.read()

现在主要目标。我到底在说什么。所以我有一些通知:

class ExpenseNotifier with ChangeNotifier 
  List<Category> _selectedCategories = [];
  Expense _currentExpense;
  int _removeId;
  Expense _editExpense;

现在,ExpenseNotifier 有几个消费者。当某些事情发生变化时,所有消费者都会更新。除了一种情况:当_editExpense 更新时,只有一个消费者应该被更新。问题是 Expense 类已经存在于通知程序中,因此所有连接到 _currentExpense 的消费者也会对 _editExpense 更新做出反应...

我现在正在使用选择器。像这样:

context.select<ExpenseNotifier, Expense>((notifier) => notifier.currentExpense);

但由于某种原因,小部件似乎也会对 _editExpense 更新做出反应...

这种情况的正确解决方案是什么?是否有可能(不定义新类型)在ExpenseNotifier 内实现它?

也许,这样的事情应该可以工作:

class EditExpense 
  final Expense expense;
  EditExpense(this.expense);

所以在这种情况下需要包装类。如果我错了,请纠正我

【问题讨论】:

可能最简单的解决方案是让一些消费者忽略 editExpense 字段 【参考方案1】:

我发现你的问题很有趣,所以我认为值得研究一下。我给出了一种一般性的答案,但我认为你会从中受益。

首先向数据类添加方法,只更新必填字段, 像这样:

class DataClass with ChangeNotifier 
  String firstString = " ";
  String secondString = " ";

  void updateFirst(String newString) 
    firstString = newString;
    notifyListeners();
  

  void updateSecond(String newString) 
    secondString = newString;
    notifyListeners();
  



现在是重构的时候了,你必须创建两个拥有自己构建方法的类(或方法)(你也可以定义两个方法并将BuildContext传递给它们):

class StringOne extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    print("StringOne build method is called");
    return Column(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: <Widget>[
        Column(
          children: [
            Text(context.select((DataClass value) => value.firstString)),
            Container(
              height: 100,
              width: 100,
              child: TextField(
                onChanged: (text) 
                  context.read<DataClass>().updateFirst(text);
                ,
              ),
            )
          ],
        )
      ],
    );
  

class StringTwo extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    print("StringTwo build method is called");
    return Column(
      children: <Widget>[
        Column(
          children: [
            Text(context.select((DataClass value) => value.secondString)),
            Container(
              height: 100,
              width: 100,
              child: TextField(
                onChanged: (text) 
                  context.read<DataClass>().updateSecond(text);
                ,
              ),
            ),
          ],
        )
      ],
    );
  

最后在描述 UI 的其他类中有这些类:

class ProviderExample extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return ListView(
      children: [StringOne(), StringTwo()],
    );
  

您可能会说它会增加冗长,实际上,重构通常会使代码更冗长,但它也使代码更清晰且易于维护。在您的情况下,它还可以防止不必要的构建。

Console :

I/flutter ( 1469): StringTwo build method is called
I/flutter ( 1469): StringTwo build method is called
I/flutter ( 1469): StringTwo build method is called
I/flutter ( 1469): StringTwo build method is called
I/zygote64( 1469): Increasing code cache capacity to 1024KB
I/flutter ( 1469): StringOne build method is called
I/chatty  ( 1469): uid=10140(com.example.stack_overflow) 1.ui identical 7 lines
I/flutter ( 1469): StringOne build method is called
I/flutter ( 1469): StringOne build method is called


【讨论】:

您好,感谢您的回复! :) 我想我有这样的东西,对我来说这是行不通的。意味着两个小部件都更新了 好吧,如果你做过类似的事情,那么一次只能调用一个构建。如果您分享更多代码,可能会对您有所帮助。

以上是关于Flutter Provider:拆分通知的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Flutter 中使用 Provider 显示来自 ChangeNotifier 的错误

如何在 Flutter 中正确重用 Provider

如何在 Flutter 中使用 Provider 正确获取 API

导航到不同路线后,Flutter 找不到正确的 Provider<Bloc>

找不到正确的Provider在带有导航流的Flutter中,此Y小部件上方

Flutter 功能型组件:跨组件状态共享(Provider)