【问题标题】:Why can't I use context.read in build(), but I can use Provider.of with listen: false?为什么我不能在 build() 中使用 context.read,但我可以使用 Provider.of with listen: false?
【发布时间】:2020-10-07 11:51:19
【问题描述】:

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

我也发现了这个话题:Is Provider.of(context, listen: false) equivalent to context.read()? 但它没有回答“为什么”。

【问题讨论】:

标签: flutter dart provider


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

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

总体而言,build 中不允许使用context.read 背后的原因在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(),
  );
}

虽然此代码本身没有错误,但这是一种反模式。 重构小部件后很容易导致未来的错误 counter 用于其他事情,但忘记将 [read] 更改为 [watch]。

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

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

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

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

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] 进行优化是非常脆弱和依赖的 关于实现细节。

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

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 不刷新的错误。

【讨论】:

  • 我个人使用provider和mobx的组合,因此不会有任何基于provider watch mechanism的反应。这些考虑只会迫使像我这样的人以毫无意义的方式遵循这些模式。
  • 但是,我使用 mobx 只是因为它不依赖于在其操作中调用诸如 notifyListeners 之类的东西。如果 Provider 提供同样的能力,我会放弃 mobx_flutter!
  • 在我看来,Provider.of 与 listen true/false 的可用性优于 context.watch/read 的可用性,因为前者适用于所有情况,因此更容易学习,而后者虽然看起来更紧凑和优雅,但不能随意使用。那么,推荐使用 context.read/watch 的原因是什么?
  • @HamedHamedi 试试 GetX,它具有与 MobX 类似的功能,但不需要代​​码生成并且不依赖于上下文(它使用基于静态而不是 InheritedWidget 的自己的机制)。
  • @SergeyMolchanovsky 在评论发表大约一个月后,我搬到了 GetX。感谢您的推荐顺便说一句?
【解决方案2】:

问题是您尝试在小部件构建完成之前调用上下文,在小部件构建完成后运行您的代码将您的代码提供给后帧回调函数。

例如:

WidgetsBinding.instance.addPostFrameCallback((_) {
    // your code in here
});

【讨论】:

    猜你喜欢
    • 2020-09-27
    • 2021-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-17
    相关资源
    最近更新 更多