Об ошибках, возникающих у провайдера флаттера - PullRequest
1 голос
/ 17 июня 2020

Я изучаю провайдер флаттера, и у меня возникла одна ошибка.

Следующий код работает.

[code1]
class Model extends ChangeNotifier {
  void save() {
    print('save');
  }
}
class Main extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => Model(),
      child: Scaffold(
        appBar: AppBar(
          title: Text('test'),
        ),
        body: NewWidget(),
      ),
    );
  }
}

class NewWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      child: Text(
        "test",
      ),
      onPressed: () {
        context.read<Model>().save();
      },
    );
  }
}

Но приведенный ниже код не работает.

[code2]
class Model extends ChangeNotifier {
  void save() {
    print('save');
  }
}

class Main extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => Model(),
      child: Scaffold(
        appBar: AppBar(
          title: Text('test'),
        ),
        body: RaisedButton(
          child: Text(
            "test",
          ),
          onPressed: () {
            context.read<Model>().save();
          },
        ),
      ),
    );
  }
}

С этим кодом при нажатии кнопки выдается следующая ошибка.

Error: Could not find the correct Provider<Model> above this Main Widget

This likely happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:

- The provider you are trying to read is in a different route.

  Providers are "scoped". So if you insert of provider inside a route, then
  other routes will not be able to access that provider.

- You used a `BuildContext` that is an ancestor of the provider you are trying to read.

  Make sure that Main is under your MultiProvider/Provider<Model>.
  This usually happen when you are creating a provider and trying to read it immediatly.

  For example, instead of:

Я не разделяю виджеты, я хочу написать один виджет, например code2.
Пожалуйста дайте мне знать, если есть хороший способ.

Спасибо!

1 Ответ

1 голос
/ 17 июня 2020

В вашем первом примере NewWidget создается с новым BuildContext, у которого уже есть доступ к его предку, поэтому этот виджет может видеть созданного вами поставщика с помощью: context.read<Model>().

Но во втором примере вы создаете и используете своего провайдера в одном и том же виджете Main, поэтому все на одном BuildContext, и когда вы запустите context.read<Model>(), flutter попытается найти в вашем дереве виджетов. чтобы найти Model, но он не найдет его, потому что вы только что его создали. Это сценарий, в котором вы могли бы использовать виджет Builder :

class Main extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => Model(),
      child: Scaffold(
        appBar: AppBar(
          title: Text('test'),
        ),
        body: Builder(
          // Here the magic happens
          // this builder function will generate a new BuilContext for you
          builder: (BuildContext newContext){
            return RaisedButton(
              child: Text(
                "test",
              ),
              onPressed: () {
                 newContext.read<Model>().save();
              },
            );
          }
        ),
      ),
    );
  }
}

Используя виджет Builder, вы можете создать новый BuildContext контейнер. может использоваться для получения информации о только что созданном вами поставщике, потому что ваш виджет Builder создается после вашего ChangeNotifierProvider и является его дочерним элементом, поэтому он может легко искать и находить эту информацию на своем родительском элементе.

Также обратите внимание на то, что вам говорят ошибки, компилятор flutter действительно умен с такого рода проблемами:

Убедитесь, что Main находится под вашим MultiProvider / Provider. Обычно это происходит, когда вы создаете поставщика и пытаетесь прочитать его немедленно.

Эти строки точно говорят вам то, что я объяснял ранее.

...