From Flutter in Action by Eric Windmill

This article is a crash course on widgets in Flutter.


Take 37% off Flutter in Action. Just enter fccwindmill into the discount code box at checkout at

Widgets: The widget tree, widget types and the State object

In general, Flutter is made of a handful of widget types. The two which we care about right now are the base of all other widget types — and .

The general goal when developing UI in a Flutter app is to compose a ton of widgets together to build the widget tree. A Flutter app is represented by a widget tree, similar to the DOM on the browser, which is also a tree-structure.

Here’s a simple visual representation of the widget tree for the counter app:

Figure 1

The process of composing widgets together is done by telling widgets that their child (or children) are more widgets. A simple example is styling some text:

return Container(     child: Padding( ①
padding: EdgeInsets.all(8.0),
child: Text("Padded Text") ②

① The container widget has a property called , which takes another widget.

② The Padding widget has a property called also, which takes a widget.

Other common properties in Flutter that allow you to pass widgets into widgets are and .

Stateless Widget

The difference between a and a is right in the name. A tracks its own internal state. A is a “dumb” widget. It doesn’t care about its configuration or what data it’s displaying. It could be passed a configuration from its parent, or the configuration could be defined within the widget, but it can’t change its own configuration. A stateless widget’s immutable.

When it comes to widget jargon, you’ll see the word configuration often.

NOTE: it’s vague, but it encapsulates everything: namely the variables passed in and its size constraints (enforced by its parent).

Imagine a button in your app. Perhaps it always says “Submit”:

class SubmitButton extends StatelessWidget {   Widget build(context) {
return Button(
child: Text('Submit');

Or, perhaps you want the button to say “Submit” in some cases and “Update” in others.

Listing 1. A widget with configuration

class SubmitButton extends StatelessWidget {   final String buttonText;                                                      ①
SubmitButton(this.buttonText); ②
Widget build(context) {
return Button(
child: Text(buttonText); ③

① Any piece of data passed to the widget is part of its configuration.

② You can omit useless constructors in Dart, but it’s needed now.

③ Pass in a variable, rather than a string literal. Flutter now knows to change this widget whenever configuration changes.

Either way, this widget is ‘dumb’ because it doesn’t update itself. It doesn’t care what the button says. Its configuration relies on parent widgets.

Also, importantly, are destroyed entirely when Flutter removes them from the widget tree. It’s important to understand that a widget shouldn’t be responsible for any data you don’t want to lose. Once it’s gone, it’s gone.

Stateful Widget

A has internal state and can manage that state. All have corresponding objects. This is the anatomy of every .

Listing 2. Anatomy of a Stateful Widget

class MyHomePage extends StatefulWidget {                    ①
@override ②
_MyHomePageState createState() => new _MyHomePageState(); ③
class _MyHomePageState extends State<MyHomePage> { ④
Widget build(BuildContext context) { ⑤
// ..

① Inherit from StatefulWidget

② Override the super class method

③ Every must have a method which returns a object

④ Your state class inherits from the Flutter object

⑤ The required method.

If you remember earlier, I said that every widget class must have a build method. As you can see above, the class, in fact, doesn’t have a build method. Every has an associated object, which has a method. You can think of the pair of and as the same entity. In fact, widgets are dumb and immutable (like a ), but their associated objects are smart and mutable.

is a , because it manages the state of the counter in the center of the app. When you tap that button, it fires a method called .

void _incrementCounter() {   setState(() { ①

is one of the methods that a Flutter object uses to manage internal state.

Figure 2 setState tells flutter to repaint


is the third important Flutter method that you have to know, after and . It only exists on the object. It more or less says “Hey Flutter, execute the code in this callback, (in this case, increase the counter variable by one), and then repaint all the widgets that rely on this state for configuration (in this case, the number on the screen in the middle of the app).” This method takes one argument, a void callback.

In our example, the object lives in the widget, and its children interact and rely on the state. When you press the button, it calls a method passed to it from . That method calls , which in turn calls the method again, repainting the widgets whose configurations have changed.

Figure 3 setState visual

This covers , but it’s worth noting that can’t execute async code. Any async work should be done before calling , because you don’t want Flutter to repaint something before the data it’s meant to display has resolved. For example, if you’re fetching a gif from a gif API on the internet, you don’t want call before the image is ready to displayed.

That’s all for now. If you want to learn more about the book, check it out on liveBook here and see this slide deck.

For more free content from Manning’s books and video courses, check out our Free Content Center.

Follow Manning Publications on Medium for free content and exclusive discounts.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store