When I use routes
in MaterialApp
the child widget's (MyHomePage
) didUpdateWidget
is called whenever I rotate the screen/open the keyboard etc.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: {
'/': (_) => MyHomePage(title: 'Flutter Demo Home Page'),
},
initialRoute: '/',
);
}
}
On the other hand, when I use the home
parameter, didUpdateWidget
is not called when I rotate the screen/open the keyboard.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
The issue I have is that I am using the Bloc pattern sample as a guide so my Bloc is disposed and recreated whenever the didUpdateWidget
is called. This means I lose all my app's state that is in the Bloc, e.g. what is selected.
@override
void didUpdateWidget(ProductSquare oldWidget) {
super.didUpdateWidget(oldWidget);
_disposeBloc();
_createBloc();
}
Why is there a difference is behavior between using routes
and home
? How can I make routes
behave like home
and not call didUpdateWidget
when the screen is rotated so the bloc is not unnecessarily recreated?
Full app sample without Bloc that rebuilds whenever I rotate the screen.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: {
'/': (_) => MyHomePage(title: 'Flutter Demo Home Page'),
},
initialRoute: '/',
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
void didUpdateWidget(MyHomePage oldWidget) {
super.didUpdateWidget(oldWidget);
print('didUpdateWidget');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
didUpdateWidget method Null safety key, the framework will update the widget property of this State object to refer to the new widget and then call this method with the previous widget as an argument. Override this method to respond when the widget changes (e.g., to start implicit animations).
initState() This is the first method called when the widget is created (after the class constructor, of course.) initState is called once and only once. It must also call super. initState() .
Mounting is the process of creating the state of a StatefulWidget and attaching it to a BuildContext.
The issue I have is that I am using the Bloc pattern sample as a guide so my Bloc is disposed and recreated whenever the didUpdateWidget is called. This means I lose all my app's state that is in the Bloc, e.g. what is selected.
This is the problem. Don't do that, it is anti-pattern.
Any widgets you make should keep in mind that they can theoretically be updated thousands of time with no change. You're supposed to verify that something changed before performing side-effects.
As such your didUpdateWidget
should be as followed:
@override
void didUpdateWidget(ProductSquare oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.product != oldWidget.product) {
_disposeBloc();
_createBloc();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With