Flutter Riverpod - 在构建方法中使用 read()

Flutter Riverpod - using read() inside build method

假设我想通过在 TextFormField 上使用 initialValue: 属性 来初始化一个文本字段,并且我需要我的初始值来自提供商。我在 docs 上读到,从构建方法内部调用 read() 被认为是不好的做法,但是从处理程序调用是好的(比如 onPressed)。所以我想知道从 initialValue 属性 调用读取是否合适,如下所示?

不,如果您正在使用钩子,则应使用 useProvider,否则应使用 ConsumerWidget / Consumer

不同之处在于,initialValue 字段是构建方法的一部分,正如您所说,onPressed 是构建方法之外的处理程序。

提供者的一个核心方面是在提供的值发生变化时优化重建。在构建方法中使用 context.read 会抵消此优势,因为您没有收听提供的值。

强烈建议在匿名函数(onChangedonPressedonTap 等)中使用 context.read,因为这些函数正在检索提供的值 在函数执行时。 这意味着函数将始终使用该提供者的当前值执行,而无需监听提供者。读取提供者的其他方法使用监听器,在匿名函数的情况下,它更昂贵且不必要。

在您的示例中,您想要设置 TextFormFieldinitialValue。以下是如何使用 hooks_riverpod and 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 只会重建其子项,因为只有它们依赖于提供的数据。