Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
1 answer
This article has a good explanation of lifting state up in Flutter.
Let's say for example that we have a
BlueSquare
widget that displays the number of times it has been tapped. Each click on the square automatically updates the text displayed with the updated total number of clicks on that square. Let's say then that we wanted to have a set ofBlueSquares
and all theBlueSquares
in that set display the accumulated number of clicks the user has done.
This means the number of clicks is a state shared by all the BlueSquare
objects.
(Grammar and some minor phrasing corrected in quote above.)
Instead of making BlueSquare
a StatefulWidget
, we make it a StatelessWidget
and make its parent a StatefulWidget
. The StatefulWidget
, BlueSquareParent
, keeps track of the number of clicks. It passes the number of clicks to the BlueSquare
widget's constructor so that BlueSquare
widget can display the current click count.
class BlueSquare extends StatelessWidget{
final int numClicks;
BlueSquare({
required this.numClicks
}) : super();
Widget build(BuildContext context){
Container(
color: Colors.blue,
height: 30,
width: 30
child: TextButton(
child: const Text("$numClicks")
)
);
}
}
class BlueSquareParent extends StatefulWidget {
BlueSquareParentState createState() => BlueSquareParentState();
}
class BlueSquareParentState extends State<BlueSquareParent>{
//Initialize the number of clicks to 0
int numClicksTotal = 0;
@override
Widget build(){
return Scaffold(
body: Column(
children: [
BlueSquare(numClicks: numClicksTotal),
BlueSquare(numClicks: numClicksTotal)
]
)
);
}
}
In the BlueSquare
example, we need to return the number of clicks to the BlueSquareParent
widget so it knows how many there are. We can do this by passing a callback method to the BlueSquares
that will let them update the number of clicks in BlueSquareParent
.
class BlueSquare extends StatelessWidget{
final int numClicks;
final Function callback;
BlueSquare({
required this.numClicks,
required this.callback
}) : super();
Widget build(BuildContext context){
Container(
color: Colors.blue,
onTap: (){
callback();
}
height: 30,
width: 30
child: TextButton(
child: const Text("$numClicks")
)
);
}
}
class BlueSquareParent extends StatefulWidget {
BlueSquareParentState createState() => BlueSquareParentState();
}
class BlueSquareParentState extends State<BlueSquareParent>{
//Initialize the number of clicks to 0
int numClicksTotal = 0;
@override
Widget build(){
return Scaffold(
body: Column(
children: [
BlueSquare(numClicks: numClicksTotal, callback: addClick),
BlueSquare(numClicks: numClicksTotal, callback: addClick)
]
)
);
}
void addClick(){
setState((){
numClicksTotal++;
});
}
}
(All code adapted from the examples in the article.)
Another example: This YouTube tutorial shows how to lift up state for TextFormFields
so that the values put into those fields are stored in a parent widget. The child widget (RangeSelectorTextFormField
) has a TextFormField
in it and receives a callback method just like the BlueSquare
widget in the first example. When the text in the field is saved, the callback method is called. In the parent widget, we create a function that sets either the minimum value or the maximum value variable in the parent widget, depending on which text field we're creating, and pass that as the callback method for the RangeSelectorTextFormField
. Then, when the text in the the TextFormField
is saved, RangeSelectorTextFormField
calls the callback method, which sets the associated variable in the parent widget.
Flutter documentation recommends using Provider
instead of lifting up state this way if you're doing anything much more complicated than the example above.
(Original post on StackOverflow here)
0 comment threads