flutter_bloc 库中的存储库提供程序在推送新路由时不提供存储库

Posted

技术标签:

【中文标题】flutter_bloc 库中的存储库提供程序在推送新路由时不提供存储库【英文标题】:Repository provider in the flutter_bloc library doesn't provide repository with when pushing new route 【发布时间】:2020-01-25 22:58:14 【问题描述】:

我正在使用 flutter_bloc 库来构建我的应用程序。除了 BlocProvider,我还在使用 Repository Provider,因为我将在整个应用程序中广泛使用特定的存储库。但是我在 context 方面遇到了问题。以下是我的代码的 sn-ps:

ma​​in.dart

void main() async 
  .......
  appRepository _appRepository = AppRepository();
  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
      .then((_) 
    runApp(
      BlocProvider(
        builder: (context) =>
            AuthenticationBloc(appRepository: _appRepository)..dispatch(AppStarted()),
        child: App(appRepository: _appRepository,),
      ),
    );
  );


class App extends StatelessWidget 

............
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
        builder: (BuildContext context, AuthenticationState state) 
       .....
          if (state is AuthenticationUnauthenticated) 
            return SafeArea(
              top: false,
              bottom: false,
              child: RepositoryProvider(
                builder: (context) => _appRepository,
                child: LoginPage(firebaseMessaging: _firebaseMessaging),
              ),
            );
          
      ......

        ,
      ),
    );
  

登录表单中的注册按钮:

register_button.dart

class RegisterButton extends StatelessWidget 
  final FirebaseMessaging _firebaseMessaging;

  RegisterButton(
    Key key,
    @required FirebaseMessaging firebaseMessaging,
  )  : assert(firebaseMessaging != null),
        _firebaseMessaging = firebaseMessaging,
        super(key: key);

  @override
  Widget build(BuildContext context) 
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text("Don't have an account?", style: TextStyle(color: Colors.black)),
        SizedBox(width: 4.0),
        GestureDetector(
          child: Text("Register here!",
              style: TextStyle(
                  color: Color(0xFF585B8D), fontWeight: FontWeight.w500)),
          onTap: () 
            Navigator.of(context).push(
              MaterialPageRoute(builder: (context) 
                return RegisterPage(
                  firebaseMessaging: _firebaseMessaging,
                );
              ),
            );
          ,
        )
      ],
    );
  

register_page.dart

class RegisterPage extends StatelessWidget 
  final FirebaseMessaging _firebaseMessaging;

  RegisterPage(
    Key key,
    @required FirebaseMessaging firebaseMessaging,
  )  : assert(firebaseMessaging != null),
        _firebaseMessaging = firebaseMessaging,
        super(key: key);

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: BlocProvider(
        builder: (context) => RegisterBloc(
          appRepository: RepositoryProvider.of<AppRepository>(context),
          firebaseMessaging: _firebaseMessaging,
        ),
        child: RegisterForm(),
      ),
    );
  

问题:

当我点击登录表单上的注册按钮时,我收到一条错误消息:

No ancestor could be found starting from the context that was passed to RepositoryProvider.of<AppRepository>().

This can happen if:
1. The context you used comes from a widget above the RepositoryProvider.
2. You used MultiRepositoryProvider and didn't explicity provide the RepositoryProvider types.

Good: RepositoryProvider<AppRepository>(builder: (context) => AppRepository())
Bad: RepositoryProvider(builder: (context) => AppRepository()).

The context used was: BlocProvider<RegisterBloc>(dirty, state: _DelegateWidgetState#a87b2(lifecycle state: created))

为什么会出现此错误?如果我将存储库提供程序作为 blocprovider 的子项,并将应用程序作为主函数中的子存储库提供程序,然后在 App() 中删除单个存储库提供程序,则此问题似乎已解决。我猜问题是从按钮推送材料页面路径。我认为我不了解上下文或提供程序在 Flutter 中的确切工作方式。我认为提供商会查找存储库/块的小部件树,推送路由是否会破坏这种连续性?

【问题讨论】:

【参考方案1】:

当您使用Navigator.of(context).pushNavigator.of(context).pushNamed 时,推送的小部件不是调用Navigator.of(context).pushNavigator.of(context).pushNamed 的小部件的子级,此小部件是包含给定的Navigator 的最近实例的子级context,在你的情况下,Navigator 是由MaterialApp 创建的,所以如果你想将RepositoryBloc 提供给不同的routesProvider 必须是@ 的父级987654333@,在你的情况下必须是MaterialApp的父母。

【讨论】:

以上是关于flutter_bloc 库中的存储库提供程序在推送新路由时不提供存储库的主要内容,如果未能解决你的问题,请参考以下文章

flutter_bloc - 为啥在 UI 而不是后端声明存储库?

flutter_bloc - 每个 Bloc 有多个存储库,还是只有一个?

服务库中的 ASP.NET 标识

ZF2 Doctrine - 使用查询构建器如何指向存储库中的自定义方法

如何在现有存储库中的 GitHub 页面上发布 React 应用程序?

存储库中的 Symfony DQL 查询