我对这个框架很陌生,并且使用提供程序包来进行状态管理,在其中遇到了changeNotifierProvider
和ChangeNotifierProvider.value
,但是我无法区分它们的用例。
我用ChangeNotifierProvider
代替了ChangeNotifierProvider.value
,但没有按预期工作。
答案 0 :(得分:22)
让我们逐步进行。
扩展了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
是many types of providers中Provider package的其中之一。如果您已经有一个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
。如果您在ChangeNotifier
的{{1}}类的initState()
方法中初始化了StatefulWidget
类,则可能会发生这种情况。
在这种情况下,您将不想创建State
的全新实例,因为这会浪费您已经完成的所有初始化工作。使用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
类实例的地方。同样,不要尝试在此处创建新实例。
答案 1 :(得分:2)
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()被调用。
答案 2 :(得分:1)
是ChangeNotifierProvider.value和create函数之间的重要区别。当您在单个列表或网格项目中使用Provider时,Flatter会在离开屏幕时删除项目,并在重新进入屏幕时重新添加项目,在这种情况下,实际发生的是Flutter重用了窗口小部件本身,而只是数据附加到它的改变。因此,Flatter回收了相同的小部件,不会破坏它 并重新创建它。当我们将Provider与create函数一起使用时。
ChangeNotifierProvider(
create: (_) => new MyChangeNotifier(),
child: ...
)
☝☝☝这里的内容随时间而变化,我们的提供商将不会接我们。
在单个列表或网格项目中,我们应使用提供者点值。
ChangeNotifierProvider.value(
value: new MyChangeNotifier(),
child: ...
)
答案 3 :(得分:0)
官方文档有帮助吗?
DO 使用ChangeNotifierProvider.value提供现有的
series: <LineSeries<SalesData, String>>[ LineSeries<SalesData, String>( dataSource: <SalesData>[ SalesData('Jan', 35), SalesData('Feb', 28), SalesData('Mar', 34), SalesData('Apr', 32), SalesData('May', 40) ],
:
ChangeNotifier
不要使用默认构造函数重用现有的
ChangeNotifierProvider.value( value: variable, child: ... )
。
ChangeNotifier
也请作者检查一下Github issue。
答案 4 :(得分:0)
基本上,带有builder(Provider v3)或create(Provider v4)参数的ChangeNotifierProvider是处置提供程序,此提供程序拥有状态源并管理其生存期。值提供者仅引用状态源,但不管理其生存期。 在处理提供程序时,builder或create参数提供了用于创建状态源的功能。在值提供程序中,有一个值参数,该参数引用状态源,您负责根据需要创建和处置状态源。