本文介绍了为什么我不能在 build() 中使用 context.read,但我可以将 Provider.of 与 listen: false 一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

文档中说这些是一样的,context.read只是Provider.of(context, listen: false)的快捷方式.如果我尝试在构建方法中使用 context.read ,控制台中也会出现错误,但它没有解释原因.

It's stated in the docs that these are the same, and context.read is just a shortcut for Provider.of<x>(context, listen: false).There's also an error in the console if I try to use context.read in a build method, but it doesn't explain the reason.

我也发现了这个话题:是Provider.of(context, listen: false) 等价于 context.read()?但它没有回答为什么".

I also found this topic: Is Provider.of(context, listen: false) equivalent to context.read()?But it doesn't answer "why".

推荐答案

  • context.read 不允许在 build 中使用,因为在那里使用非常危险,并且有更好的解决方案.

    • context.read is not allowed inside build because it is very dangerous to use there, and there are much better solutions available.

      Provider.of 允许在 build 中用于向后兼容.

      Provider.of is allowed in build for backward-compatibility.

      总的来说,build 中不允许使用 context.read 的原因在 其文档:

      Overall, the reasoning behind why context.read is not allowed inside build is explained in its documentation:

      不要在构建内部调用 [read] 如果该值仅用于事件:

      Widget build(BuildContext context) {
        // counter is used only for the onPressed of RaisedButton
        final counter = context.read<Counter>();
      
        return RaisedButton(
          onPressed: () => counter.increment(),
        );
      }
      

      虽然这段代码本身没有问题,但这是一种反模式.重构widget后很容易在未来导致错误将counter用于其他事情,但忘记将[read]更改为[watch].

      While this code is not bugged in itself, this is an anti-pattern. It could easily lead to bugs in the future after refactoring the widget to use counter for other things, but forget to change [read] into [watch].

      考虑在事件处理程序中调用 [read]:

      CONSIDER calling [read] inside event handlers:

      Widget build(BuildContext context) {
        return RaisedButton(
          onPressed: () {
            // as performant as the previous previous solution, but resilient to refactoring
            context.read<Counter>().increment(),
          },
        );
      }
      

      这与之前的反模式有相同的效率,但没有存在易碎的缺点.

      This has the same efficiency as the previous anti-pattern, but does not suffer from the drawback of being brittle.

      不要使用 [read] 来创建具有永不改变的值的小部件

      DON'T use [read] for creating widgets with a value that never changes

      Widget build(BuildContext context) {
        // using read because we only use a value that never changes.
        final model = context.read<Model>();
      
        return Text('${model.valueThatNeverChanges}');
      }
      

      虽然如果其他事情发生变化不重建小部件的想法是很好,这不应该用 [read] 来完成.依赖 [read] 进行优化是非常脆弱和依赖的关于实现细节.

      While the idea of not rebuilding the widget if something else changes is good, this should not be done with [read]. Relying on [read] for optimisations is very brittle and dependent on an implementation detail.

      考虑使用 [select] 过滤不需要的重建

      CONSIDER using [select] for filtering unwanted rebuilds

      Widget build(BuildContext context) {
        // Using select to listen only to the value that used
        final valueThatNeverChanges = context.select((Model model) => model.valueThatNeverChanges);
      
        return Text('$valueThatNeverChanges');
      }
      

      虽然比 [read] 更冗长,但使用 [select] 更安全.它不依赖于 Model 上的实现细节,它使不可能有我们的 UI 不刷新的错误.

      While more verbose than [read], using [select] is a lot safer. It does not rely on implementation details on Model, and it makes impossible to have a bug where our UI does not refresh.

      这篇关于为什么我不能在 build() 中使用 context.read,但我可以将 Provider.of 与 listen: false 一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-30 18:07