skip to Main Content

I am building a registration flow to practice flutter and bloc.

In my app I nested routes for base url ‘/registration’. I wrapped my Material App with my blocprovider. What I want to achieve is to save phonenumber to my state in my initial route and consume it in the following page.

Currently, my app saves the state in initial route, but as soon as it navigates to following page a new instance of bloc is created, hence I am not able to access saved state there. I figured that I need to pass existing context to navigator’s builder. Yet I have no success refactoring my code that way. How can I refactor my code so that the MaterialPageRoute’s builder callback doesn’t give me new build context?

Thank you!

Here is the parent registration code where routes are generated:



class RegisterFlowState extends State<RegisterFlow> {
  final _navigatorKey = GlobalKey<NavigatorState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Navigator(
        key: _navigatorKey,
        initialRoute: 'register/phonenumber',
        onGenerateRoute: _onGenerateRoute,
      ),
    );
  }
}

Route _onGenerateRoute(RouteSettings settings) {
  WidgetBuilder builder;
  switch (settings.name) {
    case 'register/phonenumber':
      builder = (_) => const CollectPhonenumberPage();
      break;
    case 'register/otp':
      builder = (_) => const OtpPage();
      break;
    default:
      throw Exception('Invalid route: ${settings.name}');
  }
  return MaterialPageRoute<void>(builder: builder, settings: settings);
}

The first page where I save the state and push to new url.

ElevatedButton(
            onPressed: () {
              phoneNumberBloc.add(UpdatePhoneNumberEvent(phoneController.text));
              Navigator.of(context).pushReplacementNamed('register/otp')
            },
            child: const Text('Kaydet'),
          ),

The second page where I want to consume the state.

BlocBuilder<PhoneNumberBloc, PhoneNumberState>(
            builder: (context, state) => Text('${state.data}'),
          )

I consulted these links and tried several of the solutions but none of them solved my problem text text

2

Answers


  1. you could pass the bloc to blocProvider.value:

    like this:

    Route _onGenerateRoute(RouteSettings settings) {
      switch (settings.name) {
        case 'register/phonenumber':
          return MaterialPageRoute<void>(
            builder: (_) => const CollectPhonenumberPage(),
          );
        case 'register/otp':
          return BlocProvider.value(
            value: context.read<PhoneNumberBloc>(),
            child: const OtpPage(),
          );
        default:
          throw Exception('Invalid route: ${settings.name}');
      }
    }
    
    Login or Signup to reply.
  2. You can define a function that takes the current context as a parameter and returns the widget that should be displayed

    Example:

    class RegisterFlowState extends State<RegisterFlow> {
      final _navigatorKey = GlobalKey<NavigatorState>();
      final phoneNumberBloc = PhoneNumberBloc();
    
      @override
      void dispose() {
        phoneNumberBloc.close();
        super.dispose();
      }
    
      Widget _wrapWithBlocProvider(Widget child) {
        return BlocProvider.value(
          value: phoneNumberBloc,
          child: child,
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Navigator(
            key: _navigatorKey,
            initialRoute: 'register/phonenumber',
            onGenerateRoute: (RouteSettings settings) {
              WidgetBuilder builder;
              switch (settings.name) {
                case 'register/phonenumber':
                  builder = (BuildContext context) {
                    return _wrapWithBlocProvider(const CollectPhonenumberPage());
                  };
                  break;
                case 'register/otp':
                  builder = (BuildContext context) {
                    return _wrapWithBlocProvider(const OtpPage());
                  };
                  break;
                default:
                  throw Exception('Invalid route: ${settings.name}');
              }
              return MaterialPageRoute<void>(builder: builder, settings: settings);
            },
          ),
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search