Bloc: How to handle BLOC architecture for this

Created on 25 Jun 2020  路  2Comments  路  Source: felangel/bloc

There is very good amount of examples but not a single complex one

Now lets say this is my route design

Home->Visit Plans->Visit Plan Rows->Retailer Detail->Sales (on sales, products, basket, calculations etc.)

Now from top to down, meaning on creating sales, i have to update all of them till Visit Plans route.

For example, Updating is visited flag for retailer, or Completed flag for Visit Plan when sales created.

I already implemented an architecture for this with a Bloc for each route and providing previous BLoc on child route but i am not sure is this the correct way to handle it. For now, its working perfectly but still i want some opinion.

This is my router class with Blocs from top to sales screens:

class Router {
  final _visitPlansBloc = VisitPlansBloc(
    visitPlansRepository: DBVisitPlansRepository(),
  );

  final _visitPlanRowsBloc = VisitPlanRowsBloc(
    visitPlanRowsRepository: DBVisitPlanRowsRepository(),
  );

  final _retailerBloc = RetailerBloc(
    retailerRepository: DBRetailerRepository(),
  );

  Route<dynamic> generateRoute(RouteSettings settings) {
    switch (settings.name) {
      case RouteNames.startRoute:
        return MaterialPageRoute(builder: (_) => SplashPage());
      case RouteNames.loginRoute:
        return MaterialPageRoute(builder: (_) => LoginPage());
      case RouteNames.homeRoute:
        return MaterialPageRoute(
            builder: (_) => MultiBlocProvider(providers: <BlocProvider>[
                  BlocProvider<SyncBloc>(
                    create: (context) => SyncBloc(syncService: SyncService(), userBloc: BlocProvider.of<UserBloc>(context)),
                  )
                ], child: HomePage()));
      case RouteNames.visitPlanRoute:
        return MaterialPageRoute(builder: (_) => BlocProvider.value(value: _visitPlansBloc, child: VisitPlanPage()));
      case RouteNames.visitPlanRowsRoute:
        var data = settings.arguments as VisitPlanModel;
        return MaterialPageRoute(builder: (_) => BlocProvider.value(value: _visitPlansBloc, child: BlocProvider.value(value: _visitPlanRowsBloc, child: VisitPlanRowPage(visitPlanModel: data))));
      case RouteNames.visitPlanRowDetailRoute:
        var data = settings.arguments as VisitPlanRowModel;
        return MaterialPageRoute(
            builder: (_) => MultiBlocProvider(providers: <BlocProvider>[
                  BlocProvider<VisitPlansBloc>.value(value: _visitPlansBloc),
                  BlocProvider<VisitPlanRowsBloc>.value(value: _visitPlanRowsBloc),
                  BlocProvider<RetailerBloc>.value(value: _retailerBloc)
                ], child: RetailerDetailPage(visitPlanRowModel: data)));
      case RouteNames.salesConfirmationRoute:
        var data = settings.arguments as VisitPlanRowModel;
        return MaterialPageRoute(
            builder: (_) => MultiBlocProvider(providers: <BlocProvider>[
                  BlocProvider<VisitPlansBloc>.value(value: _visitPlansBloc),
                  BlocProvider<VisitPlanRowsBloc>.value(value: _visitPlanRowsBloc),
                  BlocProvider<RetailerBloc>.value(value: _retailerBloc),
                  BlocProvider<OrderMainBloc>(
                    create: (context) => OrderMainBloc(
                      orderMainRepository: DBOrderMainRepository(),
                    )..add(LoadOrderMain(data.vphId)),
                  ),
                  BlocProvider<OrderProductsBloc>(
                    create: (context) => OrderProductsBloc(orderMainBloc: BlocProvider.of<OrderMainBloc>(context), productRepository: DBProductRepository(), visitPlanId: data.vphId),
                  ),
                  BlocProvider<OrderProductsFilterBloc>(
                    create: (context) => OrderProductsFilterBloc(orderProductsBloc: BlocProvider.of<OrderProductsBloc>(context)),
                  )
                ], child: SalesConfirmationPage(visitPlanRowModel: data)));
      default:
        return MaterialPageRoute(
            builder: (_) => Scaffold(
                  body: Center(child: Text('No route defined for ${settings.name}')),
                ));
    }
  }

  void dispose() {
    _visitPlansBloc.close();
    _visitPlanRowsBloc.close();
    _retailerBloc.close();
  }
}
question

Most helpful comment

Hi @callawey 馃憢
Thanks for opening an issue!

The approach you've provided seems totally reasonable. One suggestion for potentially improving/simplifying things would be to use nested Navigators for each "feature" or "flow" and that way you can provide the blocs required above the Navigator and not need to pass the blocs through each route push via BlocProvider.value.

For example:

BlocProvider(
  create: (context) => FeatureABloc(),
  child: Navigator(onGenerateRoute: (_) => FeatureAPage.route()),
);
class FeatureAPage extends StatelessWidget {
  static Route route() {
    return MaterialPageRoute(builder: (_) => FeatureAPage());
  }

  @override
  Widget build(BuildContext context) { ... }
}

With this approach the FeatureABloc instance is available even across multiple MaterialPageRoutes within FeatureAPage. Hope that helps 馃憤

All 2 comments

Hi @callawey 馃憢
Thanks for opening an issue!

The approach you've provided seems totally reasonable. One suggestion for potentially improving/simplifying things would be to use nested Navigators for each "feature" or "flow" and that way you can provide the blocs required above the Navigator and not need to pass the blocs through each route push via BlocProvider.value.

For example:

BlocProvider(
  create: (context) => FeatureABloc(),
  child: Navigator(onGenerateRoute: (_) => FeatureAPage.route()),
);
class FeatureAPage extends StatelessWidget {
  static Route route() {
    return MaterialPageRoute(builder: (_) => FeatureAPage());
  }

  @override
  Widget build(BuildContext context) { ... }
}

With this approach the FeatureABloc instance is available even across multiple MaterialPageRoutes within FeatureAPage. Hope that helps 馃憤

Closing for now but feel free to comment with additional questions and I'm happy to continue the conversation 馃憤

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MahdiPishguy picture MahdiPishguy  路  3Comments

RobPFarley picture RobPFarley  路  3Comments

shawnchan2014 picture shawnchan2014  路  3Comments

komapeb picture komapeb  路  3Comments

nerder picture nerder  路  3Comments