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:
CheckoutPage is pushed on the stack from the cart page
User Selects to add new location
Selects TextField
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