1

My project is structured with Blocs and Statefull widget. Which worked fine until now. Everytime I focus on a Textfield it rebuilds the entire chain, meaning all the routes behind it. I mean when routes are pushed one route can't access the context of the other routes right?

MaterialApp
   -> Home(context)

//pushed a route

MaterialApp
  -> NewPage(context) //it's doesn't interfere with Home
  -> Home(context)

So how does it happens to rebuilds everything? Only this particular rebuilding of widget is causing the issue other wise everything else is fine.

Overview of what happens:

  1. CheckoutPage is pushed on the stack from the cart page

  2. User Selects to add new location

  3. Selects TextField

  4. All the previous routes are rebuild

Codes: This is how my routes are defined

routes: {
...
'/checkout': (context) => BlocProvider(
      bloc: CheckoutBloc(),
      child: BlocProvider( //statefull widget
        bloc: LocationBloc(),
        child: CheckoutPage(),
      ),
    ),
'/locations/new': (context) => BlocProvider(
          bloc: NewLocationBloc(),
          child: NewLocationModal(),
        )
...
}

All the widgets are Statefull. The checkout page contains list of widgets.

class _CheckoutPageState extends State < CheckoutPage > {
  final Key _scaffold = GlobalKey < ScaffoldState > ();
  //Pages
  //1. Cart Summary
  //2. Address
  //3. Appoint Schdule
  //4. Payment
  //5  Confirmation
  int initialData = 0;
  List < Widget > _pages = [
    CartSummary(),
    LocationPage(),
    AppointmentSchedule(),
    Payment(),
    Confirmation()
  ];
  List < String > _pageTitle = [
    'Cart Summary',
    'Address',
    'Schedule Appointment',
    'Payment',
    'Confirmation'
  ];
  final PageController controller = PageController(initialPage: 0);
  @override
  Widget build(BuildContext context) {
    final CheckoutBloc bloc = BlocProvider.of < CheckoutBloc > (context);
    return BlocProvider(
      bloc: cartBloc,
      child: Scaffold(
        resizeToAvoidBottomInset: true,
        key: _scaffold,
        body: PageView(
          key: PageStorageKey('checkout'),
          onPageChanged: (int index) {
            bloc.changePage(index);
          },
          controller: controller,
          children: _pages,
        ),
      ),
      // ),
    );
  }
}

Now when I push to a new route both named/unamed and click on any TextField it rebuilds the previous routes which are on stack and the Blocs get re-instantiated.

class _NewLocationModalState extends State < NewLocationModal > {
  static final _scaffoldKey = GlobalKey < ScaffoldState > ();
  static final _form = GlobalKey < FormState > ();
  final TextEditingController _name = TextEditingController();
  @override
  Widget build(BuildContext context) {
    final NewLocationBloc bloc = BlocProvider.of < NewLocationBloc > (context);
    return Scaffold(
      key: _scaffoldKey,
      resizeToAvoidBottomInset: true,
      appBar: AppBar(
        automaticallyImplyLeading: false,
        leading: IconButton(
          icon: Icon(Icons.close),
          onPressed: () {
            Navigator.pop(context, null);
          },
        ),
        title: Text('New address'),
      ),
      body: SingleChildScrollView(
        child: Form(
          key: _form,
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 18),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: < Widget > [
                  Container(
                    color: Colors.lightGreenAccent,
                    height: 300,
                    child: Center(
                      child: Text('TODO// ADD Gmaps'),
                    ),
                  ),
                  TextFormField(
                    // autofocus: true,
                    decoration: InputDecoration(hintText: 'Client Name'),
                    controller: _name,
                    validator: (val) {
                      if (val.length <= 0) return "Can't be left blank";
                      return null;
                    },
                  ),
                ],
              ),
          ),
        ),
      ),
    );
  }
}

Is this a expected behavior to rebuild the previous routes too?

How do I structure my project to solve this issue?

There is a closed GitHub issue but there isn't anything helpful in it. https://github.com/flutter/flutter/issues/37878

Nadeem Siddique
  • 1,988
  • 4
  • 14
  • 20
  • This is working as intended. Please see https://github.com/flutter/flutter/issues/11655 for more details, but basically, you should always assume that Navigation change will rebuild all widgets already in the tree. You need to restructure your blocs to avoid this problem. I'm not sure exactly what is needed, but in general, I think blocs should be lifted out of Navigation, perhaps outside of `MaterialApp` whenever possible. – David L. Nov 27 '19 at 15:42
  • Um, isn't the question yours? – David L. Nov 27 '19 at 18:22
  • I want to close it mate. thanks for the reference to issue. – Nadeem Siddique Nov 27 '19 at 18:33

0 Answers0