Flutter auto_route | How do I wrap a route with BlocProvider?
Asked Answered
K

3

7

So, I'm using the auto_route package for navigation in my app and flutter_bloc for state management. When I was using the old Navigator, I could just wrap a route with a BlocProvider. For example:

class Router {
  static Route<dynamic> generateRoute(RouteSettings settings) {
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(
          builder: (_) => BlocProvider( // wrapped Home with BlocProvider
            create: (context) => SubjectBloc(),
            child: Home(),
          ),
        );
      case '/feed':
        return MaterialPageRoute(builder: (_) => Feed());
    }
  }
}

Now, auto_route uses annotations to generate a routing file. How would I go around providing provider context to the route?

Knudson answered 14/6, 2021 at 13:26 Comment(0)
K
8

We have our page widget (state/less/ful) implement AutoRouteWrapper

class HomePage extends StatelessWidget implements AutoRouteWrapper{
  .....
 @override
 Widget wrappedRoute(context){
   return BlocProvider(
            create: (context) => HomeBloc(),
            child:  this, // this as the child Important!
          );
   }

}
Knudson answered 14/6, 2021 at 13:54 Comment(5)
this is scoped I realisedBiffin
I have PageTwo and PageThree that accessed through PageOne. I implemented AutoRouteWrapper in PageOne, but why cannot access the bloc inside PageTwo and PageThree. The error is Error: Could not find the correct Provider<YourBloc>.Capable
@Knudson How we can mock this bloc for this page?Futtock
@Futtock What do you mean by mock? You can provide a bloc/cubit that you'll implement later.Knudson
how we can write widget tests for this page? Here with wrapper we are giving bloc, however in widget test we have to pass MockHomeBloc instead of HomeBloc, how we can achieve this with autorouteWrapper?Futtock
P
7

The answer depends on how your routes are constructed, I'll show you how I achieve this.

For nested routes (When you provide children to your routes), you can use a wrapper. You can wrap your bloc provider(s) around the child and it will provide the bloc to all children screens.

/// routes

AutoRoute(
    page: SupportWrapper,
    name: 'SupportRouter',
    path: 'support',
    children: [
        AutoRoute(
            page: HelpSupportScreen,
            path: '',
        ),
        AutoRoute(
            page: MessageUsScreen,
            path: 'issue',
        ),
    ],
),
/// build method of [support_wrapper.dart]

@override
Widget build(BuildContext context) {
  return MultiBlocProvider(
    providers: [
      BlocProvider(
        create: (context) => _supportCubit,
      ),
    ],
    child: const AutoRouter(),
  );
}

If you are not using a wrapper widget, e.g. its a single screen with no children routes, I would create a separate widget to wrap the BlocProvider around the screen.

class SupportScreen extends StatelessWidget {
  const SupportScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => _supportCubit
      child: const _SupportScreen(),
    );
  }
}

class _SupportScreen extends StatelessWidget {
  const _SupportScreen({Key? key}) : super(key: key);

// rest of your screens code...
Pliam answered 15/6, 2021 at 14:5 Comment(2)
That something I tried and it works! The developer of the library suggested that I should implement AutoRouteWrapper.Knudson
Great! if you found my answer helpful, don't forget to upvote it 😉 or mark it as answered if it answered your questionPliam
F
1

You can also use a custom route builder.

Route<T> myCustomRouteBuilder<T>(BuildContext context, Widget child, CustomPage<T> page){            
  return PageRouteBuilder(            
    fullscreenDialog: page.fullscreenDialog,            
    // this is important            
    settings: page,            
    pageBuilder: (,__,___) => BlocProvider( // wrapped page with BlocProvider
      create: (context) => SubjectBloc(),
      child: child,
    ),
  );            
}

@AutoRoute(
  replaceInRouteName: 'Page,Route',
  routes: [
    // ...
    CustomRoute(
      path: '/'
      page: FeedPage
      // ...
      customRouteBuilder: myCustomRouteBuilder,
      // ...
    ),
    // ...
  ]
)

where FeedPage is your the Feed widget. Each page in auto_route should have a pre-defined suffix in its name as you probably already know.

Fable answered 9/3, 2023 at 16:56 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.