无法在此小部件上方找到正确的提供者 [英] Could not find the correct provider above this widget

查看:37
本文介绍了无法在此小部件上方找到正确的提供者的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用 Flutter Provider 时遇到问题...我的流程是这样的:登录用户 ID 传递给新小部件后 -> 从那里执行保存到数据库,然后重定向到新小部件(仪表板).

这是登录后小部件的代码:

返回 MaterialApp(标题:标题,主页: 脚手架(应用栏:应用栏(标题:文本(标题),),正文:列表视图(孩子们:<小部件>[容器(边距:EdgeInsets.all(8.0),孩子:卡片(形状:RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))),孩子:InkWell(onTap: () {var user = Provider.of(上下文);user.savePreference(user.user.id, "Something");user.navigateToNewPage(Dashboard(), context);打印(user.user.id);},

这有效:

user.savePreference(user.user.id, "Something");

但这会导致一个问题:

user.navigateToNewPage(Dashboard(), context);

在仪表板小部件中,我正在创建:

 小部件构建(BuildContext 上下文){var user = Provider.of(上下文);

在 UserRepository 中我有这个:

 类 UserRepository 和 ChangeNotifier {用户用户;状态_status = Status.Uninitialized;状态获取状态=>_地位;用户获取 getUser =>用户;UserRepository.instance();未来<void>导航到新页面(小部件页面,BuildContext 上下文){Navigator.push(context, MaterialPageRoute(builder: (context) => page));}

我知道这个话题已经解决了问题,但没有找到适合我的问题.

解决方案

Provider Scope

MaterialApp>提供者(屏幕 A)>屏幕 B

如果 Provider 在屏幕 A 中实例化,则在从 A → B 执行 Navigator.push 后,它将无法在屏幕 B 中访问.

为什么?

因为 Provider 是一个 InheritedWidget 并且 Navigator 在它的 Screen A context<之外使用 MaterialApp context/代码> 范围.(请参阅下面的详细信息.)

修复

Provider 移动到一个共同的父级,MaterialApp 上下文,允许屏幕 A 和 B 继承其状态/上下文.

provider(MaterialApp)>屏幕A>屏幕 B

示例

void main() {运行应用程序(我的应用程序());}class MyApp 扩展 StatelessWidget {@覆盖小部件构建(BuildContext 上下文){///将 MaterialApp 包装在 Provider 小部件中返回 ChangeNotifierProvider(创建:(上下文)=>ColorModel(),//← 创建/初始化你的状态模型孩子:材料应用程序(主页:屏幕A()),);}}

详情

供应商

  • Provider 基于 InheritedWidget.只有小部件可以继承父小部件的状态.

    • Provider 需要是任何想要访问提供"的小部件树的根小部件.状态对象.

导航器

  • Navigator.push(context) 屏幕 A 不使用屏幕 A 的 context.
    • 它使用来自 MaterialAppcontext.
  • Navigator.push(context) 其实就是Navigator.of(context).push
  • Navigator.of(context) 意味着:搜索这个上下文层次结构,直到找到一个实例化导航器的上下文
    • 默认的 NavigatorMaterialApp 中实例化.
    • 除非您明确创建/使用不同的Navigator,否则您使用的是默认值.
    • Navigatorcontext 就是MaterialAppcontext.
  • 屏幕 B 将获得那个上下文(MaterialApp),不是屏幕 A 的上下文.
    • B 是 A 的兄弟姐妹,而不是它的孩子.
    • B 不从 A 继承,即使它看起来是实例化的"context 内 A.
    • 屏幕 B 是MaterialApp context,而不是屏幕 A context.
    • Provider context 范围,如果在屏幕 A 中定义,则不覆盖屏幕 B

屏幕 A → B

Navigator.push(context, MaterialPageRoute(builder: (context) => ScreenB()))

实际上是:

Navigator.of(context).push(MaterialPageRoute(builder: (context) => ScreenB()))

就像:

Navigator.of(MaterialApp).push(MaterialPageRoute(builder: (MaterialAppContext) => ScreenB()))

所以屏幕 B 在 MaterialApp context 下,不是在屏幕 A context 下,因此无法访问屏幕 A Provider 和它的 context.

有关Provider 的类似问题,请参阅此代码示例答案.>

I have a problem using Flutter Provider... My flow is like this: After login user id is passed to new widget -> from there it preforms save to db and then it redirects to new widget (Dashboard).

And this is a code of a widget after Login:

return MaterialApp(
      title: title,
      home: Scaffold(
          appBar: AppBar(
            title: Text(title),
          ),
          body: ListView(
            children: <Widget>[
              Container(
                margin: EdgeInsets.all(8.0),
                child: Card(
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.all(Radius.circular(8.0))),
                  child: InkWell(
                    onTap: () {
                      var user = Provider.of<UserRepository>(context);
                      user.savePreference(user.user.id, "Something");
                      user.navigateToNewPage(Dashboard(), context);
                      print(user.user.id);
                    },

This works:

user.savePreference(user.user.id, "Something");

But this is causing a problem:

user.navigateToNewPage(Dashboard(), context);

In Dashboard widget I am creating this:

 Widget build(BuildContext context) {
    var user = Provider.of<UserRepository>(context);

And in UserRepository I have this:

class UserRepository with ChangeNotifier {
  User user;
  Status _status = Status.Uninitialized;

  Status get status => _status;
  User get getUser => user;

  UserRepository.instance();

Future<void> navigateToNewPage(Widget page, BuildContext context) {
    Navigator.push(context, MaterialPageRoute(builder: (context) => page));
  }

I know this topic has already solved questions, but could not find anything suitable to my problem.

解决方案

Provider Scope

MaterialApp
 > provider(Screen A)
 > Screen B

If Provider is instantiated in Screen A, it won't be accessible in Screen B after a Navigator.push from A → B.

Why?

Because Provider is an InheritedWidget and Navigator uses MaterialApp context outside its Screen A context scope. (See Details below.)

Fix

Moving Provider up to a common-parent, MaterialApp context, allows both Screen A and B to inherit its state/context.

provider(MaterialApp)
 > Screen A
 > Screen B

Example

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    /// wrap MaterialApp in Provider widget
    return ChangeNotifierProvider(
      create: (context) => ColorModel(), // ← create/init your state model
      child: MaterialApp(
          home: ScreenA()
      ),
    );
  }
}

Details

Provider

  • Provider is based on InheritedWidget. Only child widgets can inherit parent widget's state.

    • Provider needs to be the root widget for any widget tree that wants access to your "provided" state object.

Navigator

  • Navigator.push(context) on Screen A doesn't use the context from Screen A.
    • It uses context from MaterialApp.
  • Navigator.push(context) is actually Navigator.of(context).push
  • Navigator.of(context) means: search up this context hierarchy until you find a context that instantiated a Navigator
    • A default Navigator is instantiated in MaterialApp.
    • Unless you explicitly create/use a different Navigator, you're using the default.
    • Navigator's context is that of MaterialApp.
  • Screen B will get that context (of MaterialApp), not the context of Screen A.
    • B is a sibling of A, not its child.
    • B does not inherit from A, even though it appears "instantiated" inside context A.
    • Screen B is a child of MaterialApp context, not of Screen A context.
    • Provider context scope, if defined in Screen A, doesn't cover Screen B

Screen A → B

Navigator.push(context, MaterialPageRoute(builder: (context) => ScreenB()))

is actually:

Navigator.of(context).push(MaterialPageRoute(builder: (context) => ScreenB()))

which is like:

Navigator.of(MaterialApp).push(
  MaterialPageRoute(builder: (MaterialAppContext) => ScreenB())
)

So Screen B is under MaterialApp context, not under Screen A context and therefore has no access to Screen A Provider and its context.

See this answer for a code sample to a similar question about Provider.

这篇关于无法在此小部件上方找到正确的提供者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆