【发布时间】:2021-01-22 22:45:34
【问题描述】:
假设我想通过使用TextFormField 上的initialValue: 属性来初始化一个文本字段,并且我需要我的初始值来自提供者。我在docs 上读到,从构建方法内部调用read() 被认为是不好的做法,但从处理程序调用是好的(如onPressed)。所以我想知道从initialValue 属性调用读取是否可以,如下所示?
【问题讨论】:
假设我想通过使用TextFormField 上的initialValue: 属性来初始化一个文本字段,并且我需要我的初始值来自提供者。我在docs 上读到,从构建方法内部调用read() 被认为是不好的做法,但从处理程序调用是好的(如onPressed)。所以我想知道从initialValue 属性调用读取是否可以,如下所示?
【问题讨论】:
不,如果您使用挂钩,则应使用 useProvider,否则应使用 ConsumerWidget / Consumer。
不同之处在于,initialValue 字段是构建方法的一部分,就像你说的,onPressed 是一个处理程序,在构建方法之外。
提供者的一个核心方面是在提供的值发生变化时优化重建。在 build 方法中使用 context.read 会抵消这种好处,因为您没有听到提供的值。
强烈建议在匿名函数(onChanged、onPressed、onTap 等)中使用 context.read,因为这些函数会在函数执行时检索提供的值。 em> 这意味着该函数将始终使用该提供者的当前值执行,而无需侦听该提供者。读取提供程序的其他方法使用侦听器,这在匿名函数的情况下更昂贵且不必要。
在您的示例中,您想设置 initialValue 的 TextFormField。以下是您如何使用hooks_riverpod 和flutter_hooks 来完成此操作。
class HooksExample extends HookWidget {
const HooksExample({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextFormField(
initialValue: useProvider(loginStateProv).email,
);
}
}
对于不喜欢使用钩子的读者:
class ConsumerWidgetExample extends ConsumerWidget {
const ConsumerWidgetExample({Key key}) : super(key: key);
@override
Widget build(BuildContext context, ScopedReader watch) {
return TextFormField(
initialValue: watch(loginStateProv).email,
);
}
}
或者:
class ConsumerExample extends StatelessWidget {
const ConsumerExample({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer(
builder: (context, watch, child) {
return TextFormField(
initialValue: watch(loginStateProv).email,
);
},
);
}
}
主要区别在于 Consumer 只会重建其子代,因为只有它们依赖于提供的数据。
【讨论】:
initialValue: useProvider(someProvider.select((value) => value.someField)), 的事情?
someField。此外,onChanged 是否与onPressed 属于同一类别,是否在onChanged 上的onChanged 上使用read() 安全?
read 就像它的名字一样,在您调用 read 时读取值。 watch 将在您调用 watch 时读取该值,但会继续关注所提供值的更新,并在这些更新发生时更新/重建。