一尘不染

为什么不能在build()中使用context.read,但是可以将Provider.of与listen:false一起使用?

flutter

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

我也发现了这个主题:Provider.of(context,listen:false)是否等同于context.read()? 但是它没有回答“为什么”。


阅读 606

收藏
2020-08-13

共1个答案

一尘不染

  • context.read禁止在内部使用,build因为在该处使用非常危险,并且有许多更好的解决方案。

  • Provider.of允许build向后兼容。

总体而言,其文档中解释了为什么context.read不允许在内部build进行解释的原因:

*如果该值仅用于事件,则 *不要 在内部调用[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().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不会刷新的错误。

2020-08-13