Reputation: 93
I have a drawer on my main page which became bloated with content and logic. For example, I need to fetch an image, get some data from Internet and so on. After extracting Drawer in new MyCustomDrawerWidget
which extends StatefulWidget
, its state has build
function which looks like this:
@override
Widget build(BuildContext context) {
return Drawer(
child: ...
);
}
My HomePageState
has build
function which looks like this:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home page'),
),
drawer: MyCustomDrawerWidget(),
body: ...
);
}
After refactoring the code like this, I noticed how drawer does not get initialized when page loads. It would initialize just after I open the drawer, which is bad because user needs to wait for data to be loaded.
Is there a way to set eager loading on drawer to get initialized along with the page?
Upvotes: 1
Views: 2380
Reputation: 21728
Problem with having Drawer in MainPage:
Problem with having Drawer in MyCustomDrawerWidget:
I would suggest getting the hybrid
approach to solve the problem.
future
to the MyCustomDrawerWidget
(If the user opens drawer before network call completes, we can show loader based on future value)Move the logic and contents related to drawer into MyCustomDrawerWidget.
class MyCustomDrawerWidget extends StatelessWidget {
var _future;
MyCustomDrawerWidget(this._future);
@override
Widget build(BuildContext context) {
return new Drawer(
child: FutureBuilder(
builder: (context, snapshot) {
if (snapshot.hasData) {
var data = snapshot.data;
return new Text(data);
} else {
return new Text("loading");
}
},
future: _future,
),
);
}
}
And in MainPage
@override
Widget build(BuildContext context) {
val future = Future.delayed(Duration(seconds: 10), () => "new value") //network call
return Scaffold(
appBar: AppBar(
title: Text('Home page'),
),
drawer: MyCustomDrawerWidget(future),
body: ...
);
}
Hope this helps.
Upvotes: 2
Reputation: 30103
I had the same problem. The Scaffold
only attaches the drawer when necessary.
The solution: Move the data loading logic into the parent widget. You can still encapsulate it in a separate model class (e.g. DrawerModel
), but this class must be instantiated when the parent widget is initialized. Keep it in the State
of the parent. Pass DrawerModel
to your drawer widget.
You have to be a bit careful when using streams and futures, because those usually can not be resubscribed. I would recommend you to use a StreamBuilder
in the drawer widget that is connected to a BehaviorSubject
in your DrawerModel
.
That's very much the BLoC pattern. Do you need a code example?
Upvotes: 1