Easy Ways to Pass and Receive Data with Flutter Stateful and Stateless Widgets or Pages

2021 Novice App Developers Guide

Yashwardhan Deshmukh
The Startup
12 min readJan 18, 2021

--

This is the simplest and complete 2021 guide for novice flutter developers who are having trouble with passing/fetching data between their flutter app pages. With the help of this, I’ll also explain a little about writing cleaner code at the end. I personally remember having trouble with this concept as a beginnner and wasted a lot of time reading something i would never comprehend, so im here writing this to make it simpler for others to learn! Note: I wont be covering complex state management libraries like BLoC, Redux etc.

Stateful VS Stateless

Just for revision’s sake,

Stateful widgets are mutable and they update their data every time a setState((){data;}) is called.

Stateless widgets on the other hand are immutable, i.e they contain data that shouldn't change during runtime.

Module 1: Passing Data to another Stateful Widget Class.

You can find my raw files for this as a github gist here → https://git.io/JLdca

Here, we have two files (excluding main.dart): page1.dart and page2.dart . The goal is to pass Color and String datatype values from page 1 to page 2 and display a container and text having the color and the color name that we chose on page1.

So let's start, shall we?

  • page1.dart
Raised Buttons

Here on the first page, in the onPressed callbacks of the two RaisedButtons, we call the Navigator.push (to navigate to the second screen), passing the respective values of the variables, directly to the constructor of the second page. Note that the BuildContext (here context) is the same.

In the highlighted code above, we can observe that, depending on what button is pressed, different values (Colors.pink and ‘Pink’ or Colors.blueGrey and ‘Blue’) are given to the variables passedColor (Color datatype) and passedColorName (String datatype),

After these values are passed to page2.dart, the next goal is to consume these values on the second page, for which we will be using key: key, and then either use widget.passedColor / widget.passedColorName (where we will 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.dart

To use these values for coloring the container on our second page, we use keys! As Emily from the Google team quoted,

Keys preserve state when widgets move around in your widget tree. In practice, 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 to you with practice and time, for now, all you have to do is analyze and remember the syntax that I have highlighted in the code and if you want to go into the details, which I strongly recommend you do, read Emily's article on medium or watch her youtube: https://youtu.be/kn0EOS-ZiIc

note: below, i am talking about the two approaches that a begginer would comprehend, without going into a bit complicated stuff like initState.

So, There are two approaches when it comes to consuming the values,

  1. Directly using the passed value

In this case, we just use the passed value from page 1 to page 2 (never change/modify it).

We declare a final property with respective datatypes and add them to the constructor as a parameter. Now the data it’s accessible in the build function!

So, having access to the data in the build, we can just set the container’s color to widget.passedColor and it should set the value to the value we chose on page1! YIPPEE, it works!

‘${widget.passedColorName} color was passed’ (assuming user selected the blue button)

But… what if we wanted to modify the color on the second page? For this, we use the second approach

2. Storing the passed value in a different variable before using it

The additional steps this approach has from approach 1, are the ones highlighted above,

i.e We have to add parameters in _PageTwoState() which passes the values, which then we set to a different value (passedColor and passedColorName in this case), which will now behave as 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 Data from another Stateful Widget Class.

You can find my raw files for this as a github gist here → https://git.io/JLdue

What if we needed to pass data back to page one, for e.g we were making a settings/theme page for a small app. I will show you just that.

note: since flutter by default doesnt persist app data on reload, you will have to use plugins like shared preferences to wrap simple data into platform-specific persistent storage (NSUserDefaults on iOS, SharedPreferences on Android, etc.). For larger databases use sqflite and path/path provider, but thats not important now.

Here we also have two files(excluding main.dart): page1.dart and page2.dart

The goal here is to navigate to page 2, check 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 page 1 to pink.

I used Cupertino toggles instead of buttons (which would have been way easier), just to show the possibilites and also to teach a little about switches, because why not? More the knowledge the merrier it is, right?!

Two containers, which change color to pink if the respect switch is active on the second page
  • page1.dart

Here we will first wrap the Navigator.push inside an async function and await for its result. 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 wait for the function to first finish (do all the business on page2) before returning anything as a value.

This above piece 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 (here called nextPageValues), which stores values as its elements.

The code above is for the two colored containers which check if the values firstSquareColor and secondSquareColor (which we set as the values we will get from page two later) are true or false, using something called as a ternary operator in flutter,. Ternary operators have the syntax → condition ? 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.

Blue changes to pink if the value returned from the next page is true

This above grey container is the navigator for the next page. We have already made a function _navigateNextPageAndRetrieveValue, which we will now call and pass the same context to it.

RaisedButton that has an onPressed () => _navigateNextPageAndRetrieveValue(context);
  • page2.dart

Now that we have written the code in page1.dart to accept values using async-await and change container color according to the values accepted,

Our next 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 as a list to page1.

NOTE: Unless stored in device persistent storage using plugins like shared preferences, these two values above (firstValue and secondValue) will always default back to ‘false’ on app restart / re-navigation to the page.

Cupertino switches (remember to import Cupertino package)

The value is set to true in the first case, so the boolean variable firstValue is also set to true, in the second case the value is defaulted to false, since it seems to be untouched by the user, so secondValue remains set to false.

Finally!, we put these values in Navigator.pop(context, [valueOne, valueTwo]) as shown above, which should come inside an onPressed of a RaisedButton.

RaisedButton that should Navigator.pop the values

SUMMARY TIME!

In page1.dart, we had a function named _navigateNextPageAndRetriveValue (called by an onPressed of a RaisedButton later in the code with passed context), which created a new list called nextPageValues.

This new list awaited for the Navigator.push to pop the result passed as a list in page2.dart. On receiving the list of boolean values, it stored them as its elements, which later are then given to a different boolean variables (firstSquareColor and secondSquareColor) using firstSquareColor = nextPageValues[0]; and secondSquareColor = nextPageValues[1];

Then we used ternary operaters so know the value of these variables and set the color respectively!

Congrats! you completed yet another module, what a legend.

Now that we have 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 here 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 next and last module.

Module 3: Passing data between Stateless Widgets and making custom widgets to write cleaner code

You can find 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 us write less code but also makes it easier to debug and understand later on.

Four different colored containers

As we can see from the above app screenshot, we need to make four similar containers which only differ in color. Hence, instead of writing the whole container code and giving each of them the same properties like height and width again and again, we come with a cleaner solution.

We make a custom widget! and using my extreme creative skills name it StatelessTwo.

As you can see below, this new custom widget has a final class property of type Color called myColor. Then we have a constructor that will construct the object. Now inside the build, we will put the part that was supposed to be repetitive, container in this case, and assign the myColor variable to the values that are meant to be changed later. Of course, the container color in this case.

You’re all set! , now just call this widget as a child inside your StatelessOne by typing StatelessTwo(myColor: Colors.yourchoice); Also now this custom widget should work just like a container that has fixed height and width but variable color.

Bonus Knowledge! : Positional arguments vs Named Arguments for the constructor:

Positional Arguments: These simply take values in the same order as they are passed in. Syntax:

1)StatelessTwo(this.myColor, this.someOtherValue); → Constructor. 2)StatelessTwo(yourColor, yourSomeOtherValue); → Calling.

Since we have only one value (myColor) that is passed, we can use Positional Arguments, but i have used named, since i personally feel its a good practice.

Named Arguments: Sometimes we have too many arguments and it becomes hard to remember the order, hence in such cases we use named arguments. Here the order in which we pass them doesnt matter. Syntax:

1)StatelessTwo({this.myColor, this.someOtherValue}); → Constructor. 2)StatelessTwo(someOtherValue: yourSomeOtherValue, myColor: yourColor); → Calling. (see we can interchange like this and it wouldnt matter)

To conclude,

With the help of this article, I hope you understood :

  1. About the simple ways in which we could pass and fetch values from widgets, may it be a Stateful or a Stateless one.
  2. How to write cleaner code and divide your app into custom widgets.

Thank you for reading! If u have any doubts/suggestions or found something I wrote incorrectly in this article, you can feel free to put it in the comments or email me: yaashwardhan@gmail.com. I have linked the respective GitHub gist in every module. Just remember,

“Knowledge is Power. Knowledge Shared is Power Multipled”

--

--

Yashwardhan Deshmukh
The Startup

What does it mean to be conscious? Would neural networks ever be conscious? What is the true meaning of life?