问题
Suppose I want to initialize a text field by using the initialValue:
property on a TextFormField
, and I need my initial value to come from a provider. I read on the docs that calling read()
from inside the build method is considered bad practice, but calling from handlers is fine (like onPressed
). So I'm wondering if its fine to call read from the initialValue
property like shown below?
回答1:
No, you should use useProvider
if you are using hooks, or a ConsumerWidget
/ Consumer
if you are not.
The difference being, the initialValue
field is a part of the build method, and like you said, onPressed
is a handler, outside of the build method.
A core aspect of providers is optimizing rebuilds as provided values change. Using context.read
in the build method is nullifying this benefit as you aren't listening to the provided value.
Using context.read
is highly recommended in anonymous functions (onChanged
, onPressed
, onTap
, etc.) because those functions are retrieving the provided value at the time the function is executed. This means the function will always execute with the current value of that provider, without having to listen to the provider. The other methods for reading providers use a listener which is more expensive and unnecessary in the case of anonymous functions.
In your example, you wanted to set initialValue
of a TextFormField
. The following is how you could use hooks_riverpod and flutter_hooks to accomplish that.
class HooksExample extends HookWidget {
const HooksExample({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextFormField(
initialValue: useProvider(loginStateProv).email,
);
}
}
And for readers who prefer to not use hooks:
class ConsumerWidgetExample extends ConsumerWidget {
const ConsumerWidgetExample({Key key}) : super(key: key);
@override
Widget build(BuildContext context, ScopedReader watch) {
return TextFormField(
initialValue: watch(loginStateProv).email,
);
}
}
Or:
class ConsumerExample extends StatelessWidget {
const ConsumerExample({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer(
builder: (context, watch, child) {
return TextFormField(
initialValue: watch(loginStateProv).email,
);
},
);
}
}
The primary difference being that Consumer
will only rebuild its children because only they are relying on provided data.
来源:https://stackoverflow.com/questions/64253162/flutter-riverpod-using-read-inside-build-method