为什么我不能在 build() 中使用 context.read,但我可以使用 Provider.of with listen: false?
Why can't I use context.read in build(), but I can use Provider.of with listen: false?
文档中说它们是一样的,context.read
只是Provider.of<x>(context, listen: false)
的一个快捷方式。
如果我尝试在构建方法中使用 context.read
,控制台也会出现错误,但它没有解释原因。
我也找到了这个话题:
但它没有回答“为什么”。
context.read
不允许在build
里面使用,因为在那里使用非常危险,而且有更好的解决方案。
Provider.of
在 build
中被允许用于向后兼容。
总体而言,build
中不允许使用 context.read
的原因在 its documentation 中进行了解释:
DON'T call [read] inside build if the value is used only for events:
Widget build(BuildContext context) {
// counter is used only for the onPressed of RaisedButton
final counter = context.read<Counter>();
return RaisedButton(
onPressed: () => counter.increment(),
);
}
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].
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.
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}');
}
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.
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');
}
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.
问题是您尝试在小部件构建完成之前调用上下文,以便在小部件构建完成后 运行 您的代码将您的代码提供给 post 帧回调函数。
例如:
WidgetsBinding.instance.addPostFrameCallback((_) {
// your code in here
});
文档中说它们是一样的,context.read
只是Provider.of<x>(context, listen: false)
的一个快捷方式。
如果我尝试在构建方法中使用 context.read
,控制台也会出现错误,但它没有解释原因。
我也找到了这个话题:
context.read
不允许在build
里面使用,因为在那里使用非常危险,而且有更好的解决方案。Provider.of
在build
中被允许用于向后兼容。
总体而言,build
中不允许使用 context.read
的原因在 its documentation 中进行了解释:
DON'T call [read] inside build if the value is used only for events:
Widget build(BuildContext context) { // counter is used only for the onPressed of RaisedButton final counter = context.read<Counter>(); return RaisedButton( onPressed: () => counter.increment(), ); }
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].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.
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}'); }
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.
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'); }
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.
问题是您尝试在小部件构建完成之前调用上下文,以便在小部件构建完成后 运行 您的代码将您的代码提供给 post 帧回调函数。
例如:
WidgetsBinding.instance.addPostFrameCallback((_) {
// your code in here
});