【问题标题】:About errors that occur in flutter's provider关于flutter的provider中出现的错误
【发布时间】:2020-10-06 15:29:16
【问题描述】:

我正在学习 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();
      },
    );
  }
}

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

[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 这样的小部件。
有什么好的方法请告诉我。

谢谢!

【问题讨论】:

    标签: flutter state provider


    【解决方案1】:

    在您的第一个示例中,NewWidget 是使用新的 BuildContext 构建的,该 BuildContext 已经可以访问它的祖先,因此这个小部件可以看到您在那里创建的提供程序:context.read&lt;Model&gt;()

    但是,在您的第二个示例中,您正在同一个小部件Main 中创建和使用您的提供程序,因此同一个BuildContext 上的所有内容,当您运行context.read&lt;Model&gt;() 时,颤振将尝试在您的小部件中查找树找到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();
                  },
                );
              }
            ),
          ),
        );
      }
    }
    

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

    还要注意错误告诉你什么,flutter 编译器非常聪明地处理这类问题:

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

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

    【讨论】:

      【解决方案2】:

      除了上面的答案,还可以使用Provider包的Consumer类。

      import 'package:flutter/material.dart';    
      import 'package:flutter/foundation.dart';    
      import 'package:provider/provider.dart';
      
      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: Consumer<Model>(    
                builder: (context, model, _) {    
                  return RaisedButton(    
                    child: Text(    
                      "test",    
                    ),    
                    onPressed: () {    
                      context.read<Model>().save();    
                    },    
                  );    
                },    
              ),    
            ),    
          );    
        }    
      }    
      

      【讨论】:

        【解决方案3】:

        从 MultiProvider 包装 MaterialApp。并设置 Provider Class(es) 的值。

        例如:

        return MultiProvider(
          providers: [
            ChangeNotifierProvider.value(
              value: Cart(),
            ),
          ],
          child: MaterialApp(
            title: 'Perfumino',
            home: Home(),
          ),
        );
        

        【讨论】:

          猜你喜欢
          • 2022-01-19
          • 2020-11-01
          • 1970-01-01
          • 2021-09-02
          • 2021-01-17
          • 2022-10-18
          • 2020-10-24
          • 2021-10-01
          • 1970-01-01
          相关资源
          最近更新 更多