[Flutter/dart] Determine if rebuilding from the parent widget or by setState ()
Overview
When creating a page with StatefulWidget, I encountered a situation where I want to determine if it was rebuilt from the parent widget or from within the page with setState ().
More specifically, I put the page in the child widget of the Provider so that if a certain state changes, it will be reflected on the page as well.
In the case of rebuilding by Provider, it means that the state has changed, so I would like to perform processing to reflect that.
On the other hand, the change by setState () does not change the monitored state (example: switching pages of BottomNavigation), so I do not want to do this process.
( You may think that I should do it with initState (), but initState only passes the first time when built from Provider etc.)
I would like to describe how to deal with this situation.
Method
Have a bool variable in the StatefulWidget that indicates whether it is a rebuild from the parent widget
When calling the constructor of this StatefulWidget from the parent Widget (Provider, etc.), set this bool variable to true.
Perform the desired processing by referring to the value of this variable in the build() method. Then set this variable to false.
In this way, if you perform the process only once at build time, this process will not pass in the subsequent rebuild by setState ().
A concrete example is shown below.
This page can be switched between 3 pages with Bottom Navigation.
ViewModel is a class that represents a state. Create three pages based on the ViewModel instance.
I would like to perform this page creation process when the contents of the model change, but if I write it in build (), the creation process will run every time the page is switched, which is inefficient.
Therefore, we are taking the above measures.
class basePage extends StatefulWidget{
ViewModel model;
bool buildFromParent;
basePage({this.model, this.buildFromParent});
@override
State<StatefulWidget> createState() {
return basePageState();
}
}
class basePageState extends State<basePage>{
List<Widget>_pageList;
int _pageInd=0;
@override
Widget build(BuildContext context) {
if (widget.buildFromParent) {
_pageList = [APage(model: widget.model,),
BPage(model: widget.model), CPage(model: widget.model,)];
widget.buildFromParent=false; //here
}
return Scaffold(
body: _pageList[_pageInd],
bottomNavigationBar:BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today)
),
BottomNavigationBarItem(
icon: Icon(Icons.list),
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
)
],
currentIndex: _pageInd,
onTap: (index) {
setState(() {
_pageInd = index;
});
},
)
);
}
}
The code that calls this basePage is below. Set buildFromParent to true.
@override
Widget build(BuildContext context) {
return StoreProvider<AppState>(
store: store,
child: StoreConnector<AppState, ViewModel>(
distinct: true,
converter: (store)=>ViewModel.create(store),
builder: (BuildContext context, ViewModel model)=>
basePage(model: model, buildFromParent: true,) //here
)
);
}
I often use StoreProvider because I manage the state with redux.
Lastly
Actually, the first measure is to prevent rebuilding as much as possible using const etc., but I think that you may want to change the display content of the page depending on the state.
There is also an opinion that StatelessWidget is enough if you use Provider, but there are cases where you have to use StatefulWidget like BottomNavigation or DropdownButton.
In such a case, please try this method.
Recent Posts
See AllWhat want to do I want to create an input form using TextField. For example, if the input content is a monetary amount, I would like to...
What want to do There is a variable that remain unchanged once the initial value is determined. However, it cannot be determined yet when...
What want to do As the title suggests. Place two widgets in one line on the screen One in the center of the screen and the other on the...
留言