微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 Provider 的 context.read<T>() 方法触发小部件重建

如何解决使用 Provider 的 context.read<T>() 方法触发小部件重建

根据 Flutter 的文档和 this example,据我了解,Provider 包的 context.read<T>context.watch<T> 方法间的主要区别与触发小部件重建有关。您可以在任何小部件的 context.watch<T>() 方法调用 build 以访问当前状态,并在状态更改时要求 Flutter 重建您的小部件。您不能在构建方法之外使用 context.watch<T>(),因为这通常会导致细微的错误。相反,他们说,使用 context.read<T>(),它获取当前状态但不要求 Flutter 进行未来重建。

我尝试制作这个简单的应用程序:

class MyDatanotifier extends ChangeNotifier {
  String _testString = 'test';

  // getter
  String get testString => _testString;

  // update
  void updateString(String aString) {
    _testString = aString;
    notifyListeners();
  }
}

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => MyDatanotifier(),child: MyApp(),),);
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text(context.read<MyDatanotifier>().testString),body: Container(
          child: Level1(),);
  }
}

class Level1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(
          onChanged: (val) {
            context.read<MyDatanotifier>().updateString(val);
          },Text(context.read<MyDatanotifier>().testString),],);
  }
}

所有调用都针对 counter.read<T>()。应用程序的状态会发生变化,但不会使用新值重建 UI。我必须将其中一个调用更改为 counter.watch<T>() 才能重建状态。

另一方面,在 DZone's simple example 中,UI 会重建,并且所有调用都针对 context.read()。

他们的代码和我的有什么不同?为什么我不能用 counter.read() 调用重建?

解决方法

TLDR:快速浏览后,DZone 文章似乎有错误。

更长的答案

context.watch<Foo>() 做了两件事:

  1. 从树中返回状态的实例
  2. context 标记为依赖于 Foo

context.read<Foo>() 只做 1)。

每当您的 UI 依赖于 Foo 时,您都应该使用 context.watch,因为这会适当地通知 Flutter 该依赖项,并且它将被正确重建。

总的来说,它归结为这个经验法则:

  • context.watch 方法或任何其他返回 build() 的方法中使用 Widget
  • context.read 处理程序(和其他相关函数)中使用 onPressed

人们似乎不恰当地使用 context.read 的主要原因是出于性能原因。一般来说,在性能方面更喜欢 context.read 而不是 context.watch 是一种反模式。相反,如果您想限制小部件重建的频率,您应该使用 context.select。当您的值经常更改时,这将非常有用。

假设您有以下状态:

class FooState extends ChangeNotifier {
  // imagine this us updated very often
  int millisecondsSinceLastTap;

  // updated less often
  bool someOtherProperty = false;
}

如果您有一个显示 someOtherProperty 的小部件,context.watch 可能会导致许多不必要的重建。相反,您可以使用 context.select 仅取决于状态的已处理部分:

// read the property,rebuild only when someOtherProperty changes
final property = context.select((FooState foo) => foo.someOtherProperty);  
return Text('someOtherProperty: $property');

即使值经常更新,如果提供给 select 的函数的输出没有改变,小部件也不会重建:

// even though millisecondsSinceLastTap may be updating often,// this will only rebuild when millisecondsSinceLastTap > 1000 changes
final value = context.select((FooState state) => state.millisecondsSinceLastTap > 1000);
return Text('${value ? "more" : "less"} than 1 second...');

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。