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".
Every Context object comes with a Provider React component that allows consuming components to subscribe to context changes. The Provider component accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers.
What are contexts of reading? Contexts of reading are all the elements that influence how we read in different situations. The context includes: 1) the setting, 2) the text, and 3) the purpose for reading. There are two main types of reading contexts.
Useful methods in BuildContext This method is used to locate or find a widget of a particular type in the widget tree. This method will go up the widget tree from the widget it was called from, and try to locate the first widget in the tree whose type is the same one passed to the method.
context.read
is not allowed inside build
because it is very dangerous to use there, and there are much better solutions available.
Provider.of
is allowed in build
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With