#flutter #flutter-provider
#flutter #flutter-provider
Вопрос:
Предположим, я хочу инициализировать текстовое поле, используя initialValue:
свойство для a TextFormField
, и мне нужно, чтобы мое начальное значение поступало от поставщика. Я читал в документах, что вызов read()
изнутри метода сборки считается плохой практикой, но вызов из обработчиков — это нормально (например onPressed
). Итак, мне интересно, нормально ли вызывать read из initialValue
свойства, как показано ниже?
Ответ №1:
Нет, вы должны использовать useProvider
, если вы используете хуки, или ConsumerWidget
/ Consumer
, если вы этого не делаете.
Разница в том, initialValue
что поле является частью метода сборки и, как вы сказали, onPressed
является обработчиком вне метода сборки.
Основным аспектом поставщиков является оптимизация перестроек по мере изменения предоставленных значений. Использование context.read
в методе сборки сводит на нет это преимущество, поскольку вы не слушаете предоставленное значение.
context.read
Настоятельно рекомендуется использовать в анонимных функциях ( onChanged
, onPressed
, onTap
, и т. Д.), Поскольку эти функции извлекают указанное значение во время выполнения функции.Это означает, что функция всегда будет выполняться с текущим значением этого поставщика, без необходимости прослушивать поставщика. Другие методы для поставщиков чтения используют прослушиватель, который является более дорогостоящим и ненужным в случае анонимных функций.
В вашем примере вы хотели установить initialValue
a TextFormField
. Ниже показано, как вы могли бы использовать hooks_riverpod и flutter_hooks для достижения этой цели.
class HooksExample extends HookWidget {
const HooksExample({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextFormField(
initialValue: useProvider(loginStateProv).email,
);
}
}
И для читателей, которые предпочитают не использовать хуки:
class ConsumerWidgetExample extends ConsumerWidget {
const ConsumerWidgetExample({Key key}) : super(key: key);
@override
Widget build(BuildContext context, ScopedReader watch) {
return TextFormField(
initialValue: watch(loginStateProv).email,
);
}
}
Или:
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,
);
},
);
}
}
Основное отличие заключается в том, что Consumer
он будет перестраивать только свои дочерние элементы, потому что только они полагаются на предоставленные данные.
Комментарии:
1. Спасибо, вроде как подозревал это. Я ценю информацию, поэтому, если я правильно понял, я должен сделать что-то вроде
initialValue: useProvider(someProvider.select((value) => value.someField)),
?2. предполагая, что я хочу отобразить
someField
. Кроме того,onChanged
относится к той же категорииonPressed
, что и использованиеread()
safe вonChanged
на aTextFormField
?3. Ответил на ваши вопросы, расширив мой ответ. Похоже, вы удалили свою учетную запись, но надеюсь, что она все еще может помочь вам и будущим читателям.
4. Спасибо @alex-hartford, рад, что я нашел это — мне очень помогло!
5. @OmarEssam
read
, как и его имя, считывает значение во время вызоваread
.watch
считывает значение во время вызоваwatch
, но продолжает следить за обновлениями предоставленного значения и обновлять / перестраивать при появлении этих обновлений.