繁体   English   中英

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

[英]Triggering Widget Rebuilds with Provider's context.read<T>() Method

根据 Flutter 的文档和本示例,据我了解,Provider 包的context.read<T>context.watch<T>方法之间的主要区别与触发小部件重建有关。 您可以在任何小部件的build方法中调用context.watch<T>()来访问当前状态,并在状态发生变化时要求 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 的简单示例中,UI 重建,并且所有调用都是对 context.read() 的。

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

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

更长的答案

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

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

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

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

一般来说,它归结为这个经验法则:

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

人们似乎不恰当地使用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...');

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM