You Have to Pass It to Read It
Like shooting fish in a barrel Ways to Pass and Receive Data with Palpitate Stateful and Stateless Widgets or Pages
2021 Novice App Developers Guide
This is the simplest and complete 2021 guide for novice palpitate developers who are having problem with passing/fetching data between their flutter app pages. With the help of this, I'll besides explain a little nearly writing cleaner code at the terminate. I personally call back having trouble with this concept as a beginnner and wasted a lot of time reading something i would never embrace, and so im here writing this to get in simpler for others to learn! Note: I wont be covering complex country management libraries like BLoC, Redux etc.
Stateful VS Stateless
Just for revision'southward sake,
Stateful widgets are mutable and they update their information every time a setState((){information;}) is called.
Stateless widgets on the other hand are immutable, i.e they comprise data that shouldn't change during runtime.
Module 1: Passing Data to another Stateful Widget Class.
You lot can find my raw files for this as a github gist here → https://git.io/JLdca
Hither, nosotros have two files (excluding main.dart): page1.dart and page2.dart . The goal is to pass Color and String datatype values from folio one to page 2 and display a container and text having the color and the color proper name that we chose on page1.
So allow's start, shall we?
- page1.dart
Here on the first page, in the onPressed callbacks of the 2 RaisedButtons, we call the Navigator.push button (to navigate to the second screen), passing the respective values of the variables, directly to the constructor of the second folio. Note that the BuildContext (here context) is the same.
import 'page2.dart';
class PageOne extends StatefulWidget {
@override
_PageOneState createState() => _PageOneState();}
class _PageOneState extends Country<PageOne> { @override
Widget build(BuildContext context) {
return Eye(
child: Cavalcade(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('Choose color to be passed to next page'),
RaisedButton( //button 1
color: Colors.pinkish,
onPressed: () {
Navigator.button(
context,
MaterialPageRoute(
builder: (_) => PageTwo(
passedColor: Colors.pink,
passedColorName: 'Pink',
),),);},
child: Text('Pink')),
RaisedButton( //button two
colour: Colors.blueGrey,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
architect: (_) => PageTwo(
passedColor: Colors.blueGrey,
passedColorName: 'Bluish',
),),);},
child: Text('Blue'),
),],),);}}
In the highlighted lawmaking to a higher place, we can observe that, depending on what button is pressed, dissimilar values (Colors.pinkish and 'Pinkish' or Colors.blueGrey and 'Blue') are given to the variables passedColor (Color datatype) and passedColorName (Cord datatype),
Later these values are passed to page2.dart, the next goal is to consume these values on the second folio, for which we will be using key: fundamental, and then either use widget.passedColor / widget.passedColorName (where nosotros volition use the raw passed values without modification), or store them in other variables (in this case we can modify the passed values). I'll explain everything in a bit.
- page2.sprint
To use these values for coloring the container on our second page, we use keys! As Emily from the Google team quoted,
Keys preserve country when widgets move around in your widget tree. In do, this means they can be useful to preserve the user's scroll location or keep state when modifying a collection.
Scratching your head mate? Don't worry hahaaha; it'll all come up to y'all with exercise and fourth dimension, for now, all you have to do is clarify and remember the syntax that I have highlighted in the lawmaking and if yous want to go into the details, which I strongly recommend you do, read Emily'southward commodity on medium or watch her youtube: https://youtu.be/kn0EOS-ZiIc
annotation: below, i am talking almost the two approaches that a begginer would comprehend, without going into a bit complicated stuff similar initState.
So, At that place are ii approaches when information technology comes to consuming the values,
- Directly using the passed value
In this case, nosotros just use the passed value from page 1 to page 2 (never modify/modify information technology).
We declare a final property with respective datatypes and add them to the constructor as a parameter. At present the information it's accessible in the build function!
class PageTwo extends StatefulWidget { final Color passedColor;
final Cord passedColorName;
const PageTwo(
{Cardinal cardinal, this.passedColor, this.passedColorName})
: super(primal: key); // super is used to call the constructor of the base class which is the StatefulWidget here @override
_PageTwoState createState() => _PageTwoState();
}
class _PageTwoState extends State<PageTwo> {
@override
Widget build(BuildContext context) {
render Scaffold(
appBar: AppBar(
title: Text('Page two'),
automaticallyImplyLeading: false, //optional: removes the default back pointer
),
body: Column(
children: [
Container(
height: 400,
width: double.infinity,
color: widget.passedColor,
),
Text('${widget.passedColorName} color was passed'), //${} sign here prints the value of variable within it. RaisedButton(
color: Colors.grey,
onPressed: () {
Navigator.pop(context);
},
kid: Text('<- Go back'))
],),);},}
And so, having admission to the data in the build, nosotros tin just prepare the container'southward color to widget.passedColor and it should prepare the value to the value we chose on page1! YIPPEE, it works!
Simply… what if we wanted to alter the color on the 2nd page? For this, we utilise the second approach
2. Storing the passed value in a different variable before using information technology
course PageTwo extends StatefulWidget {
terminal Color passedColor;
terminal String passedColorName;
const PageTwo({Fundamental key, this.passedColor, this.passedColorName})
: super(key: primal); @override
_PageTwoState createState() => _PageTwoState(
passedColor: this.passedColor, passedColorName: this.passedColorName);
}class _PageTwoState extends State<PageTwo> {
Color passedColor;
String passedColorName;
_PageTwoState({this.passedColor, this.passedColorName}); @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page two'),
automaticallyImplyLeading: imitation, //to disable going dorsum
),
body: Cavalcade(
children: [
Container(
pinnacle: 400,
width: double.infinity,
color: passedColor,
),
Text('$passedColorName colour was passed'),
//$ and ${} is the same affair, {} is just used if its non one give-and-take RaisedButton(
color: Colors.greyness,
onPressed: () {
Navigator.popular(context);
},
kid: Text('<- Get back'))
],),);}}
The additional steps this approach has from approach 1, are the ones highlighted in a higher place,
i.e We have to add parameters in _PageTwoState() which passes the values, which then nosotros ready to a different value (passedColor and passedColorName in this case), which will now behave every bit though they were initialized with those passed values
Congratulations on completing the first module! Such a quick learner! Now put on those programmer shades and navigate with me to the next module. Got the pun? HA ha! Ha HA! Ahem, excuse me.
Module 2: Fetching Information from another Stateful Widget Class.
You can detect my raw files for this as a github gist here → https://git.io/JLdue
What if we needed to pass data back to page 1, for e.thou we were making a settings/theme folio for a small app. I volition show you just that.
note: since flutter past default doesnt persist app data on reload, you lot volition take to use plugins similar shared preferences to wrap simple data into platform-specific persistent storage (NSUserDefaults on iOS, SharedPreferences on Android, etc.). For larger databases employ sqflite and path/path provider, but thats not of import now.
Here nosotros also have 2 files(excluding main.dart): page1.dart and page2.dart
The goal here is to navigate to folio two, cheque what boolean value has the user set the Cupertino switches to, and if the value is true, then change the color of the respective container displayed on folio 1 to pink.
I used Cupertino toggles instead of buttons (which would have been way easier), just to evidence the possibilites and likewise to teach a piddling almost switches, considering why non? More than the noesis the merrier it is, correct?!
- page1.dart
Hither we will commencement wrap the Navigator.push button inside an async office and await for its result. And then on the second screen, we will pass the boolean value of the switch to the Navigator.pop back to the first screen.
Basically async and await here await for the part to first finish (practise all the concern on page2) before returning anything equally a value.
import 'package:flutter/material.dart
class PageOne extends StatefulWidget {
@override
_PageOneState createState() => _PageOneState();
}
class _PageOneState extends State<PageOne> {
bool firstSquareColor = faux; //since blue by default
bool secondSquareColor = false; //since blue by default _navigateNextPageAndRetriveValue(BuildContext context) async {
final Listing nextPageValues = await Navigator.push button(
context,
MaterialPageRoute(architect: (_) => PageTwo()),
);
setState(() {
firstSquareColor = nextPageValues[0]; //first element is stored at the 0th index for a list
secondSquareColor = nextPageValues[i];
});} //code continues below
This to a higher place slice of code, using async and await function, takes the values popped from the page2 screen.
Now to store these values (firstSquareColor and secondSquareColor), we use a list (hither called nextPageValues), which stores values as its elements.
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
tiptop: 150, width: 150,
color: firstSquareColor == fake ? Colors.blue : Colors.pink),
Container(
height: 150, width: 150,
color: secondSquareColor == false ? Colors.blue : Colors.pink),
//code continues below The code above is for the two colored containers which bank check if the values firstSquareColor and secondSquareColor (which we set equally the values nosotros will get from page two after) are truthful or faux, using something called as a ternary operator in palpitate,. Ternary operators have the syntax → status ? trueStatement : falseStatement . Hence they function as a shorter form of an if else statement.
If the value is true, that means the switch on next page has returned true (its toggled on), so we now set the color to pink.
Container(
acme: 50, width: 150,
child: RaisedButton(
height: 15,
colour: Colors.gray[700],
kid: Text(
'Next Page ->',
style: TextStyle(color: Colors.black, fontSize:
17),), onPressed: () {
_navigateNextPageAndRetriveValue(context);
}, ),),
],),);}}
This in a higher place grey container is the navigator for the next page. We have already fabricated a function _navigateNextPageAndRetrieveValue, which nosotros will at present call and pass the aforementioned context to it.
- page2.dart
Now that we have written the lawmaking in page1.dart to accept values using async-await and alter container color according to the values accepted,
Our adjacent goal is to read the value that the user has given to the Cupertino toggle on page2, which we will store in new boolean variables (called firstValue and secondValue), then Navigator.pop these values equally a list to page1.
form PageTwo extends StatefulWidget {
@override
_PageTwoState createState() => _PageTwoState();
}
class _PageTwoState extends State<PageTwo> {
bool firstValue = faux;
bool secondValue = false;
//code continues below Annotation: Unless stored in device persistent storage using plugins like shared preferences, these two values above (firstValue and secondValue) volition e'er default back to 'false' on app restart / re-navigation to the page.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Folio ii'),
automaticallyImplyLeading: faux, //to disable going to page1 when used swipe right ios gesture on the screen, because we want to pop the values, when nosotros navigate back, which we are only doing it hither with a RaisedButton
),
torso: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.middle,
children: [
Text(
'Flip to change first square color ',
textAlign: TextAlign.center,),
Container(
child: CupertinoSwitch( //get-go switch
value: firstValue,
onChanged: (bool value) {
setState(
() {
firstValue = value;
},);},),
),],),
Row(
mainAxisAlignment: MainAxisAlignment.middle,
children: [
Text(
'Flip to change second foursquare colour ',
textAlign: TextAlign.middle,
),
Container(
child: CupertinoSwitch( //2nd switch
value: secondValue,
onChanged: (bool value) {
setState(
() {
secondValue = value;
},);},
),),],),
//code continues below
The value is set to true in the kickoff case, so the boolean variable firstValue is too fix to truthful, in the second example the value is defaulted to false, since information technology seems to be untouched by the user, so secondValue remains set to fake.
Container(
height: 60,
width: 170,
child: RaisedButton(
acme: 15,
color: Colors.grey[700],
child: Text(
'<- Relieve temporarily and go to previous Folio',
textAlign: TextAlign.centre,
fashion: TextStyle(colour: Colors.black,
fontSize: xv),
),
onPressed: () {
Navigator.pop(context, [firstValue, secondValue]
); //multiple values are passed using a list
},
),),
],),);}} Finally!, we put these values in Navigator.pop(context, [valueOne, valueTwo]) as shown above, which should come up inside an onPressed of a RaisedButton.
SUMMARY TIME!
In page1.dart, nosotros had a function named _navigateNextPageAndRetriveValue (called by an onPressed of a RaisedButton afterward in the code with passed context), which created a new listing called nextPageValues.
This new list awaited for the Navigator.push to popular the consequence passed every bit a list in page2.dart. On receiving the list of boolean values, it stored them as its elements, which later are so given to a unlike boolean variables (firstSquareColor and secondSquareColor) using firstSquareColor = nextPageValues[0]; and secondSquareColor = nextPageValues[1];
Then we used ternary operaters and so know the value of these variables and set the color respectively!
Congrats! y'all completed yet another module, what a fable.
Now that we take completed the harder part, we come to a part that shows how easy it is to pass data between stateless widgets since there is not much need hither as the Widget being Stateless, itself wouldn't refresh during runtime. I will also cover how to write clean code and be a better developer in the side by side and concluding module.
Module 3: Passing information betwixt Stateless Widgets and making custom widgets to write cleaner code
You can detect my raw files for this as a github gist here → https://git.io/JLdHK
The goal here is to make a custom widget that displays a container and the color passed to it, this not only helps usa write less code simply also makes it easier to debug and sympathize later.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.night(),
home: Scaffold(
appBar: AppBar(
title: Text('Stateless/Make clean Code'),
),
body: StatelessOne(),),);}
}
class StatelessOne extends StatelessWidget {
@override
Widget build(BuildContext context) {
render Center(
child: Cavalcade(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
'Widget color tin be customised without \nhaving to retype the entire lawmaking'), StatelessTwo(myColor: Colors.green),
StatelessTwo(myColor: Colors.pink),
StatelessTwo(myColor: Colors.bluish),
StatelessTwo(myColor: Colors.orange), //calling the custom widget which we volition make below ],),);}
}
As we can see from the in a higher place app screenshot, we need to make four like containers which only differ in color. Hence, instead of writing the whole container lawmaking and giving each of them the aforementioned properties like height and width again and over again, we come with a cleaner solution.
We brand a custom widget! and using my extreme artistic skills proper name it StatelessTwo.
As you lot tin see below, this new custom widget has a final grade belongings of type Color called myColor. Then we have a constructor that will construct the object. Now within the build, we volition put the office that was supposed to exist repetitive, container in this case, and assign the myColor variable to the values that are meant to be changed later on. Of course, the container color in this example.
You're all set! , at present just call this widget as a child inside your StatelessOne by typing StatelessTwo(myColor: Colors.yourchoice); Likewise now this custom widget should piece of work just similar a container that has stock-still superlative and width but variable color.
class StatelessTwo extends StatelessWidget {
final Colour myColor;
StatelessTwo({this.myColor});
@override
Widget build(BuildContext context) {
return Container(
elevation: 120,
width: 250,
colour: myColor,
child: Centre(child: Text('Your Repetitive Widget')),
);}
} Bonus Knowledge! : Positional arguments vs Named Arguments for the constructor:
Positional Arguments: These just have values in the aforementioned society as they are passed in. Syntax:
1)StatelessTwo(this.myColor, this.someOtherValue); → Constructor. 2)StatelessTwo(yourColor, yourSomeOtherValue); → Calling.
Since we have only i value (myColor) that is passed, we can utilize Positional Arguments, simply i have used named, since i personally feel its a good exercise.
Named Arguments: Sometimes we accept as well many arguments and it becomes difficult to call back the order, hence in such cases we use named arguments. Here the lodge in which nosotros laissez passer them doesnt matter. Syntax:
one)StatelessTwo({this.myColor, this.someOtherValue}); → Constructor. two)StatelessTwo(someOtherValue: yourSomeOtherValue, myColor: yourColor); → Calling. (see we can interchange like this and it wouldnt matter)
To conclude,
With the aid of this article, I hope you lot understood :
- About the simple ways in which we could pass and fetch values from widgets, may it be a Stateful or a Stateless one.
- How to write cleaner lawmaking and divide your app into custom widgets.
Thank you for reading! If u have any doubts/suggestions or plant something I wrote incorrectly in this article, yous tin can feel free to put it in the comments or email me: yaashwardhan@gmail.com. I have linked the corresponding GitHub gist in every module. Just remember,
"Knowledge is Power. Knowledge Shared is Ability Multipled"
Source: https://medium.com/swlh/the-simplest-way-to-pass-and-fetch-data-between-stateful-and-stateless-widgets-pages-full-2021-c5dbce8db1db
0 Response to "You Have to Pass It to Read It"
Post a Comment