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

时间:2020-09-17 21:59:48

标签: flutter flutter-provider

我正在尝试使用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);
}

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

1 个答案:

答案 0 :(得分: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