问题
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.
I also found this topic: Is Provider.of(context, listen: false) equivalent to context.read()? But it doesn't answer "why".
回答1:
context.read
is not allowed insidebuild
because it is very dangerous to use there, and there are much better solutions available.Provider.of
is allowed inbuild
for backward-compatibility.
Overall, the reasoning behind why context.read
is not allowed inside build
is explained in 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.
来源:https://stackoverflow.com/questions/62432759/why-cant-i-use-context-read-in-build-but-i-can-use-provider-of-with-listen