Flutter basics
Note: If you’ve worked with languages that are statically typed, null-safe, and allow for declaring variables (im)mutable then Dart should feel pretty readable to you. After having spent the last 15 years or so working in really “fast” scripting languages like Powershell and Python, it has taken me some getting used to:
Final <Dart> CanSeem (Very?<Verbose> atTimes)=> toMe;
I recently had the opportunity to learn the basics of DartLang and the Flutter framework. Most guides are focused on the UI creation, or are focused on qualifying Dart structure/syntax with well known software engineering concepts. Not having any experience in any languages that feel similar to Dart, the latter wasn’t very helpful for me. There are two concepts I was missing when I started working on my app that I now think are most important to understand when starting out: State management and Class inheretence .
State management
This was a wholly new concept to me. Most of the code I’ve done up to this point takes data in at run time, performs functions, and reports or saves data as output. The most user interaction I’ve had to account for was a switch-style CLI menu. When I was researching Flutter builds I kept seeing State Management packages getting thrown around and realized it was a concept I’d have to tackle, but wasn’t exactly sure what aspects of my app would require it. If you’re a seasoned Mobile developer you’d have a gameplan for state management at scale before starting your build. If you are me, you start making those decisions at the moment you try to write your first widget. Every UI component in Flutter is a Widget, and every Widget inherits from one of two base classes: Stateless or Stateful.
Stateful vs Stateless widgets initially seems like a simple concept but can get tricky when you remember in Flutter you will at times be dealing with a series of idgets nested inside of widgets. Exactly which widget needs to be Stateful? The good news is in the simple app you’re making as a beginner, if you choose the wrong widget state you’ll be fine. If you incorrectly choose Stateful, your App will be a little less efficient at compile time, no biggie. You will know pretty quickly if you incorrectly chose Stateless, when you find yourself trying to configure the setState command and realize it’s not available. It’s simple enough to change the widget being extended and move your stateful logic to the the state class:
class SettingsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold();
}
}
Becomes:
class SettingsPage extends StatefulWidget {
@override
_SettingsPageState createState() => _SettingsPageState();
}
class _SettingsPageState extends State<SettingsPage> {
@override
Widget build(BuildContext context) {
return Scaffold();
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
}
All of this was pretty overwhelming for me until I realized this is pretty boilerplate. You’ll see the same format over and over for Stateful widgets. You extend the class to create your widget, then you use the CreateState function, which is a method of the StatefulWidget class.
When setState is called, it rebuilds the related widget (calls the widgets build method). This refreshes the widget so the UI accurately displays updated information. The example you’ll see thrown around a lot is a counter, when you click the button the counterVariable would be incremented. But the UI was already rendered. You need setState to call the re-build. If you have multiple widgets that share the same “stateful” information, that information should be stored in a parent widget that can call for a rebuild in the child widgets.
📌 I don’t recommend using state management repos until you have a firm grab on the basics of the built-in functionality. That being said, the official Flutter docs pretty quickly jump to using Provider, a 3rd party repo, in their Docs for examples. Make of that what you will.
Class Inheritance
You have to accept that everything is a widget. There’s only one rule: Null safety? No, not that. You can get around that(?). It is that you don’t ask WHY everything is a widget. Maybe it is because Widgets is people?
“Widgets are used to describe all aspects of a user interface, including physical aspects such as text and buttons to lay out effects like padding and alignment.” - the Docs
But widgets really are objects being instantiated from a class. And those objects inherit from existing classes. It’s the foundation of Flutter. I’ve worked with classes a little in Python, but I have not found occasion to create a class that inherits from another. Flutter feels like you’re getting paid per inheritance. It’s filthy with it. Once you get on board with that, and method @overrides, the picture really starts to come together. I tend to enjoy “walking out” code to make sense of it, but when it comes to certain UI elements I’ve found its easier to just accept that a Scaffold is a widget, or an AppBar is a widget, and not feel the need to dig into their classes beyond the superficial. That being said, consider how you want to organize your code in terms of separate .dart files and private versus public methods and parameters, because “refactoring” this stuff later can be difficult with the object oriented nature of the widgets. It can be more complicated to unwind later than you’d think.