Flutter Provider:拆分通知的正确方法
Flutter Provider: proper way to split notifying
我正在尝试使用 Provider
拆分小部件的触发更新。
我使用的是最新的 Flutter
版本。在应用程序中,我还使用了 context.select()
、context.watch()
和 context.read()
.
现在进入主要目标。我到底在说什么。所以我有一些通知程序:
class ExpenseNotifier with ChangeNotifier {
List<Category> _selectedCategories = [];
Expense _currentExpense;
int _removeId;
Expense _editExpense;
}
现在,ExpenseNotifier
有几个消费者。当某些事情发生变化时,所有消费者都会得到更新。除了一种情况:当 _editExpense
更新时,只应更新一个消费者。问题是 class Expense
已经存在于通知程序中,因此所有连接到 _currentExpense
的消费者也会对 _editExpense
更新做出反应...
我现在正在使用选择器。像这样:
context.select<ExpenseNotifier, Expense>((notifier) => notifier.currentExpense);
但出于某种原因,小部件似乎也会对 _editExpense
更新做出反应...
对于这种情况,正确的解决方案是什么?是否有可能(不定义新类型)在 ExpenseNotifier
内实现它?
可能,像这样的东西应该有效:
class EditExpense {
final Expense expense;
EditExpense(this.expense);
}
所以在这种情况下需要包装器 class。如果我错了请纠正我
我发现你的问题很有趣,所以我认为它值得研究。我给出了一种笼统的回答,但我认为你会从中受益。
首先向数据添加方法 class,这将仅更新必填字段,
像这样:
class DataClass with ChangeNotifier {
String firstString = " ";
String secondString = " ";
void updateFirst(String newString) {
firstString = newString;
notifyListeners();
}
void updateSecond(String newString) {
secondString = newString;
notifyListeners();
}
}
现在是重构的时候了,你必须制作两个 classes(或方法),它们将有自己的构建方法(你也可以定义两个方法并将 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 中有了这些 classes:
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
我正在尝试使用 Provider
拆分小部件的触发更新。
我使用的是最新的 Flutter
版本。在应用程序中,我还使用了 context.select()
、context.watch()
和 context.read()
.
现在进入主要目标。我到底在说什么。所以我有一些通知程序:
class ExpenseNotifier with ChangeNotifier {
List<Category> _selectedCategories = [];
Expense _currentExpense;
int _removeId;
Expense _editExpense;
}
现在,ExpenseNotifier
有几个消费者。当某些事情发生变化时,所有消费者都会得到更新。除了一种情况:当 _editExpense
更新时,只应更新一个消费者。问题是 class Expense
已经存在于通知程序中,因此所有连接到 _currentExpense
的消费者也会对 _editExpense
更新做出反应...
我现在正在使用选择器。像这样:
context.select<ExpenseNotifier, Expense>((notifier) => notifier.currentExpense);
但出于某种原因,小部件似乎也会对 _editExpense
更新做出反应...
对于这种情况,正确的解决方案是什么?是否有可能(不定义新类型)在 ExpenseNotifier
内实现它?
可能,像这样的东西应该有效:
class EditExpense {
final Expense expense;
EditExpense(this.expense);
}
所以在这种情况下需要包装器 class。如果我错了请纠正我
我发现你的问题很有趣,所以我认为它值得研究。我给出了一种笼统的回答,但我认为你会从中受益。
首先向数据添加方法 class,这将仅更新必填字段, 像这样:
class DataClass with ChangeNotifier {
String firstString = " ";
String secondString = " ";
void updateFirst(String newString) {
firstString = newString;
notifyListeners();
}
void updateSecond(String newString) {
secondString = newString;
notifyListeners();
}
}
现在是重构的时候了,你必须制作两个 classes(或方法),它们将有自己的构建方法(你也可以定义两个方法并将 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 中有了这些 classes:
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