towhid
towhid

Reputation: 3288

Convenient way to share BLoC between multiple screen

I am looking for the most convenient way to share bloc in different screens/pages without providing at top of the material app. For example I have a Customer bloc, which is required in CustomerListScreen and CustomerDetailsScreen. The bloc is created in CustomerListScreen and passed it to the CustomerDetailsScreen while navigating.

Navigator.context, MaterialPageRoute(builder: (context) => CustomerDetailsScreen(context.read<CustomerBloc>())));

This is the procedure I am following right now. Looking for any better approach available out there..

Upvotes: 9

Views: 11516

Answers (3)

Muhaiminur Rahman
Muhaiminur Rahman

Reputation: 3152

Change the context name to other name and pass that context like below

 @override
 Widget build(BuildContext context) {
 return MultiBlocProvider(
    providers: [
      BlocProvider<AuthBloc>(
        create: (BuildContext context) => AuthBloc(),
      ),
    ],
    child: Scaffold(
        appBar: AppBar(
          title: const Text("Log In"),
          centerTitle: true,
          backgroundColor: ContactColors.primaryColor,
        ),
        backgroundColor: ContactColors.offwhite,
        body: BlocConsumer<AuthBloc, AuthState>(listener: (c, state) {
          if (state is AuthError) {
            print("error state");
          } else if (state is AuthSuccess) {
            print("success");
          }
        }, builder: (c, state) {
          if (state is AuthLoading) {
            print("loader");
            return loginbox(c);
          } else {
            return loginbox(c);
          }
          // return widget here based on BlocA's state
        })));
}

Upvotes: -1

Arin Faraj
Arin Faraj

Reputation: 408

You could make the Bloc a required field of the page, something like this:

class CustomerDetailsScreen extends StatelessWidget { 
  CustomerDetailsScreen(this.mybloc);

  final Bloc mybloc;

  @override
  Widget build(BuildContext context) {
    return  BlocProvider.value(
      value: mybloc,
      child: Text('Body...'),
    );
  }
}

Now, even if you use a package like AutoRoute you will still be able to provide the bloc to the page route.

Even though I don't like this solution because what if you navigated through a url then you can't pass the bloc to it, for this i recommend to use nested navigation read this

it will look something like this if you use AutoRoute

@MaterialAutoRouter(              
  replaceInRouteName: 'Page,Route',              
  routes: <AutoRoute>[              
    AutoRoute(                            
      page: BlocProviderPage,              
      children: [              
        AutoRoute(page: CustomerListScreen),              
        AutoRoute(page: CustomerDetailsScreen),          
      ],              
    ),             
  ],              
)              
class $AppRouter {} 
class BlocProviderPage extends StatelessWidget {          
  @override          
  Widget build(BuildContext context) {          
    return BlocProvider(
            create: (context) => MyBloc(),       
            child: AutoRouter(),          
    );          
  }          
}  

This way both pages will have access to the bloc and you cant navigate to them without a BlocProviderPage being a parent of them

Upvotes: 6

user18309290
user18309290

Reputation: 8320

Use BlocProvider.value.

BlocProvider can be used to provide an existing bloc to a new portion of the widget tree. This will be most commonly used when an existing bloc needs to be made available to a new route. In this case, BlocProvider will not automatically close the bloc since it did not create it.

BlocProvider.value(
  value: context.read<CustomerBloc>(),
  child: CustomerDetailsScreen(),
);

Upvotes: 11

Related Questions