关于 flutter 的 provider 中发生的错误

日高岳*_*高岳大 7 provider state flutter

我正在了解 flutter 的提供者,但我遇到了一个错误。

以下代码有效。

[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();
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

但是下面的代码不起作用。

[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();
          },
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

使用此代码,按下按钮时会输出以下错误。

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:
Run Code Online (Sandbox Code Playgroud)

我不分离小部件,我想编写一个像 code2 这样的小部件。
请让我知道是否有任何好的方法。

谢谢!

Leo*_*tto 10

在你的第一个例子,NewWidget是建立一个新的BuildContext,已经可以访问它的祖先,所以这个小工具可以看到您与创建有供应商:context.read<Model>()

但是,在您的第二个示例中,您正在同一个 Widget 中创建和使用您的提供程序,Main因此所有内容都在同一个BuildContext,并且当您运行context.read<Model>()flutter 时,将尝试在您的 Widget 树中查找以找到Model,但它不会找到它因为你刚刚创建了它。这是您可以使用Builder Widget的场景:

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();
              },
            );
          }
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

通过使用BuilderWidget,您可以创建一个新BuildContext的可用于检索有关您刚刚创建的提供程序的信息,这是因为您的 Builder 小部件是在您的 ChangeNotifierProvider 之后构建的,并且它是它的子项,所以它可以轻松查找并找到有关其父级的此信息。

还要注意错误告诉您的内容,flutter 编译器在处理此类问题时非常聪明:

确保 Main 在您的 MultiProvider/Provider 下。这通常发生在您创建提供程序并尝试立即读取它时。

这些行准确地告诉您我之前解释过的内容。