问题描述
文档中说这些是一样的,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 insidebuild
because it is very dangerous to use there, and there are much better solutions available.Provider.of
允许在build
中用于向后兼容.Provider.of
is allowed inbuild
for backward-compatibility.总的来说,
build
中不允许使用context.read
的原因在 其文档:Overall, the reasoning behind why
context.read
is not allowed insidebuild
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 一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!