寻找提供者上下文的颤振问题

Posted

技术标签:

【中文标题】寻找提供者上下文的颤振问题【英文标题】:Flutter problem with finding provider context 【发布时间】:2019-12-06 06:47:36 【问题描述】:

我对 Flutter Provider 模式有疑问。将用户重定向到新屏幕后,找不到提供程序。

在我之前的问题之后 (Could not find the correct provider above this widget) 我写了这段代码:

class NewRoute extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    final title = 'Tap to select';
    return MaterialApp(
        title: title,
        home: Scaffold(
          appBar: AppBar(
            title: Text(title),
          ),
          body: NewRouteBody()
        ));
  


class NewRouteBody extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    var user = Provider.of<UserRepository>(context);
    return ListView(...)

我做了同样的事情,但我再次收到错误消息,指出在此小部件上方找不到正确的提供程序 (NewRouteBody)。

试图以某种方式修复它,谷歌搜索了几个小时的答案,但没有成功......

感谢任何帮助。

编辑

这是UserRepository,其中包含模式:

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

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

编辑 2:

带有 ChangeNotifier 的代码 sn-p:

void main() => runApp(MyApp());
class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.red,
      ),
      home: HomePage(),
    );
  


class HomePage extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return ChangeNotifierProvider<UserRepository>(
      builder: (context) => UserRepository.instance(),
      child: Consumer<UserRepository>(
        builder: (context, UserRepository userRepository, _) 
          switch (userRepository.status) 
            case Status.Uninitialized:
              return Login();
            case Status.Unauthenticated:
              return Login();
            case Status.Authenticating:
            case Status.Authenticated:

              if(userRepository.getUser.isPrefSet == 0)
                return Selection();
              
              return Dashboard();
          
        ,
      ),
    );
  

【问题讨论】:

您的 sn-p 中根本没有提供程序。它在哪里? 我已经编辑了我的问题...我认为我可以使用这个var user = Provider.of&lt;UserRepository&gt;(context); 通过所有应用程序访问user 谢谢,但您的典型ChangeNotifierProvider()Provider() 在哪里? 我再次编辑了我的问题。这就是应用的核心。它将用户重定向到仪表板或登录屏幕。从仪表板用户可以转到新屏幕,在这种情况下 NewRoute... 我知道在我之前的评论中使用用户变量可以访问任何屏幕中的用户属性。 非常感谢! 【参考方案1】:

问题是:

您的ChangeNotifierProvider 位于Home 内,但您正尝试在外部 Home 访问它。

提供者是有范围的。这意味着如果它位于小部件树内,则只有其后代可以访问它。因此,在您的代码中,只有 Home 可以从提供程序读取。

要解决这个问题,请将提供程序移到 MaterialApp 上方:

ChangeNotifierProvider<UserRepository> (
  builder: (context) => UserRepository(),
  child: MaterialApp(
    home: Home(),
  ),
)

【讨论】:

非常感谢。不过得测试一下。就像我说的那样,我的目标是拥有某种用户会话,所有小部件都可以访问(更新的)UserRepository 成员......提供者似乎是一个很好的解决方案,但我不知道它的范围。 如果提供者在MaterialApp以上,则类似于全局变量。 太棒了!抱歉,还有一个问题……是否所有提供程序类型(ChangeNotifier、Provider 等)都重建所有正在侦听的小部件?我正在考虑性能,因为我的应用程序将有很多屏幕(小部件)。我只需要变量作为全局变量。 ChangeNotifier 是这个的好选择吗? 只有依赖于“全局”的小部件才会在该值更改时更新。所以不用担心【参考方案2】:

您首先需要创建 Provider 并将其放置在使用上方的树中。 例如,在您的情况下:

  Widget build(BuildContext context) 
final title = 'Tap to select';
return MaterialApp(
    title: title,
    home: Scaffold(
        appBar: AppBar(
          title: Text(title),
        ),
        body: Provider<UserRepository> (
          builder: (context) => UserRepository(),
            dispose: (context, val) => val.dispose(),
            child: NewRouteBody())
    ));

【讨论】:

我编辑了我的问题。登录后我想设置用户首选项。如果我创建新的Provider,那么它将重新初始化UserRepository,如果我没记错的话,它将是null

以上是关于寻找提供者上下文的颤振问题的主要内容,如果未能解决你的问题,请参考以下文章

颤振导航未定义的“上下文”

颤振显示上下文操作快捷方式不起作用

未在颤振自定义应用程序栏中获取脚手架上下文

无上下文的颤振本地化

图片 Asset Studio 在颤振项目中不可用

颤振未定义的名称“上下文”。尝试将名称更正为已定义的名称,或定义名称