Почему я не могу использовать context.read в build (), но могу использовать Provider.of с listen: false? - PullRequest
9 голосов
/ 17 июня 2020

В документации указано, что это одно и то же, а context.read - это просто ярлык для Provider.of<x>(context, listen: false). Если я попытаюсь использовать context.read в методе сборки, в консоли также появится ошибка, но это не объясняет причину.

Я также нашел этот topi c: Is Provider. of (context, listen: false) эквивалентно context.read ()? Но он не отвечает «почему».

1 Ответ

13 голосов
/ 17 июня 2020
  • context.read не допускается внутри build, потому что там очень опасно использовать, и есть гораздо лучшие решения.

  • Provider.of разрешено в build для обратной совместимости.

В целом, причина того, почему context.read не допускается внутри build, объясняется в документации :

НЕ вызывать [чтение] внутри сборки, если значение используется только для событий:

Widget build(BuildContext context) {
  // counter is used only for the onPressed of RaisedButton
  final counter = context.read<Counter>();

  return RaisedButton(
    onPressed: () => counter.increment(),
  );
}

Хотя этот код сам по себе не содержит ошибок, это анти-шаблон. Это может легко привести к ошибкам в будущем после рефакторинга виджета, чтобы использовать counter для других целей, но забудьте заменить [read] на [watch].

СЧИТАЙТЕ вызов [read ] внутри обработчиков событий:

Widget build(BuildContext context) {
  return RaisedButton(
    onPressed: () {
      // as performant as the previous previous solution, but resilient to refactoring
      context.read<Counter>().increment(),
    },
  );
}

Эффективность такая же, как и у предыдущего антишаблона, но не имеет такого недостатка, как хрупкость.

НЕ используйте [чтение] для создания виджетов со значением, которое никогда не меняется

Widget build(BuildContext context) {
  // using read because we only use a value that never changes.
  final model = context.read<Model>();

  return Text('${model.valueThatNeverChanges}');
}

Хотя идея не перестраивать виджет, если что-то еще изменится, хороша, этого не следует делать с помощью [читать]. Полагаться на [чтение] для оптимизации очень непросто и зависит от деталей реализации.

РАССМАТРИВАЙТЕ использование [select] для фильтрации нежелательных перестроек

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');
}

Хотя более подробно чем [читать], использование [select] намного безопаснее. Он не зависит от деталей реализации Model и делает невозможным наличие ошибки, при которой наш пользовательский интерфейс не обновляется sh.

...