Home > Software design >  How to set correctly the BlocProvider between two different routes (screens)?
How to set correctly the BlocProvider between two different routes (screens)?

Time:01-26

I am using Bloc for my application, however I was doing something wrong and that is, providing all BlocProvider creates in the MaterialApp and I would not like to follow that bad practice.

Let's suppose that when I navigate to ScreenA, we create the Bloc as follows :

      case PageNames.screenA:
        return PageTransition( // Some class that navigates
          duration: const Duration(milliseconds: 400),
          child: BlocProvider<ScreenABloc>(
            create: (context) => ScreenABloc(),
            child: const ScreenAPage(),
          ),
      );

Now inside ScreenA, I will do a navigation to ScreenB, and everything is fine, however inside ScreenB at the bottom of my widget tree I want to access the ScreenABloc again, but I can't assign a BlocProvider.value because I get :

ProviderNotFoundException (Error: Could not find the correct Provider<ScreenABloc> above this Welcome Widget

return BlocProvider.value(
      value: BlocProvider.of<ScreenABloc>(context),
      child: child ...
);

So I am not sure how to get the supplier that has already been created, or if I should re-create it or what to do in those cases.

CodePudding user response:

You can create a method of creating BlocProvider in the screen itself, then you can use that method for navigating and creating providers for you.

Here's an example:

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

   static Widget create() {
    return MultiBlocProvider(
      providers: [
        BlocProvider<SignInBloc>(
          create: (BuildContext context) => SignInBloc(),
        ),
      ],
      child: const SignInScreen(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

CodePudding user response:

you should use BlocProvider.value when you push a new route:

/// declare the bloc
final _screenABloc = ScreenABloc();

then use it in both ScreenA and ScreenB

case PageNames.screenA:
  return PageTransition( // Some class that navigates
    duration: const Duration(milliseconds: 400),
    child: BlocProvider.value(
      value: _screenABloc,
      child: const ScreenAPage(),
    ),
  );

case PageNames.screenB:
  return PageTransition( // Some class that navigates
    duration: const Duration(milliseconds: 400),
    child: BlocProvider.value(
      value: _screenABloc,
      child: const ScreenBPage(),
    ),
  );

CodePudding user response:

Correction

Using all BlocProviders in the starting of the file is not considered bad practice.


Why ?

According to official docs

By default, BlocProvider will create the bloc lazily, meaning create will get executed when the bloc is looked up via BlocProvider.of(context).


What is the efficient way ?

Use MultiBlocProvider in the start of your app and leave the memory problems to BlocProvider it will take care of initialization and disposing as and when required.

  • Related