Не удается получить доступ к провайдеру во флаттере - PullRequest
0 голосов
/ 23 февраля 2020

У меня есть простой класс провайдера: -

class DataProvider with ChangeNotifier {
   int count;
   void updateCount() {
     count = count + 1;
     notifyListeners();
   }
}

Я присоединяю этого провайдера к следующему классу: -

class MyWidget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => DataProvider(),
      child: Scaffold(
        body: raisedButton(
          onPressed: () {
            Provider.of<DataProvider>(context).updateCount();
          }
           child: Text("Click!")
         ),
       ),
     ),
   }

и он выдает мне следующую ошибку: -

 I/flutter (32011): Error: Could not find the correct Provider<DataProvider> above this MyWidget 
 Widget
 I/flutter (32011): To fix, please:
 I/flutter (32011):   * Ensure the Provider<DataProvider> is an ancestor to this MyWidget Widget
 I/flutter (32011):   * Provide types to Provider<DataProvider>
 I/flutter (32011):   * Provide types to Consumer<DataProvider>
 I/flutter (32011):   * Provide types to Provider.of<DataProvider>()
 I/flutter (32011):   * Ensure the correct `context` is being used. 

В чем может быть причина этого?

Редактировать: - Работает нормально, когда я получаю доступ к провайдеру из любого дочернего виджета виджета, в котором я определил , ChangeNotifierProvider.

Ответы [ 2 ]

1 голос
/ 23 февраля 2020

Это потому, что вы звоните Provider.of<DataProvider>(context).updateCount(), используя неправильный context. Вы используете context, предоставленный методом build, который выше по иерархии, чем поставщик, к которому вы пытаетесь обратиться. Вам нужно использовать context, который принадлежит потомку (ниже по иерархии) Провайдера.

Обернуть ваш Scaffold в Builder виджет, который выставляет новый context при этом уровень в иерархии виджетов, и используйте вместо этого этот контекст.

Вы также можете использовать Consumer, хотя это не будет оптимальным в вашем примере, потому что Consumer будет перестраиваться каждый раз, когда notifyListeners() вызывается в провайдер, который будет избыточным, потому что ваш пользовательский интерфейс не изменяется.

1 голос
/ 23 февраля 2020

Вам нужно обернуть raisedButton в Consumer.

Виджет «Потребитель» имеет две основные цели:

Он позволяет получить значение от поставщика, когда мы не имеет BuildContext, который является потомком указанного поставщика, и, следовательно, не может использовать Provider.of. Этот сценарий обычно происходит, когда виджет, который создает провайдера, также является одним из его потребителей, как в следующем примере:

@override
Widget build(BuildContext context) {
  return ChangeNotifierProvider(
    create: (_) => Foo(),
    child: Text(Provider.of<Foo>(context).value),
  );
}

В этом примере генерируется исключение ProviderNotFoundException, поскольку Provider.of вызывается с BuildContext, который является предком поставщика.

Вместо этого мы можем использовать виджет Consumer, который будет вызывать Provider.of со своим собственным BuildContext.

Используя Consumer, предыдущий пример станет:

@override
Widget build(BuildContext context) {
  return ChangeNotifierProvider(
    create: (_) => Foo(),
    child: Consumer<Foo>(
      builder: (_, foo, __) => Text(foo.value),
    },
  );
}

Это не вызовет исключение ProviderNotFoundException и будет правильно создавать текст. Он также будет обновлять текст при каждом изменении значения foo.

См .: https://pub.dev/documentation/provider/latest/provider/Consumer-class.html

...