This post is a personal perspective and does not represent the views or opinions of the Flutter team, or Google more broadly.

State management is a hot topic in the Flutter community

and on, and on, and on…

Why is this topic so popular? Why does everyone seem to be confused about it? Why are so many developers begging for solutions to “state management”?

Let’s start with the basics.

What is state?

If I asked 100 developers to define “state,” I would end up with many answers:

The data (whatever that is!).

All the variables in all the StatefulWidgets.

All the variables in the entire application.

A store, like a Redux or Flux store.

The behavior of the app at a given moment in time (this is my definition!).

What is state management?

If I asked 100 developers to define “state management,” I would still end up with many answers:

Like Redux or Flux or BLoC (there are always some developers who think listing examples is the same as defining a concept).

How data gets into/out of a store.

How information flows through a system.

How business logic interacts with the UI.

Databases.

Hexagonal architecture.

Who knows? (this is my definition)

You’re confusing so many concepts!

Debates about “state management” are an exercise in demonstrating the importance of words and definitions. The ill-defined concept of state management is an amalgamation of numerous independent behaviors:

Data persistence

Information flow

Programming paradigms

I/O (especially networking and caching)

Application architecture

Presentation behavior

UI templating

etc.

You will find no universal solution to any individual behavior listed above. You will absolutely never find a universal solution to ALL behaviors listed above. And that’s a good thing, because if such a solution existed, your job as a software developer certainly wouldn’t!

As far as I can tell, “state management” is a catch-all term that really means “software engineering.” Therefore, when we see developers asking “How do I manage state?” or “How does Flutter handle state management?”, it’s tantamount to asking “How do I engineer software?” I don’t know, how many years do I have to answer your question?!

Communicating more effectively, and getting answers to your questions

If you have found yourself asking how to “manage state” and you’re unhappy with the responses, it’s because no one really knows what you mean.

If you want to know how to make network calls and cache the results, then ask that.

If you want to setup a centralized Redux-style store within your app, then ask that.

If you want to understand the fundamentals of how to hydrate a Flutter widget hierarchy with information, then ask that.

If you want to find out how others have setup their business rules and relationships, and tied those artifacts to the Flutter widget hierarchy, then ask that.

If you want to understand the various ways in which one might integrate hardware capabilities like audio, accelerometers, or Bluetooth, then ask that.

The important step for you to take is to deeply investigate the root of your question. If you couldn’t use the words “manage” or “state,” how would you ask your same question?

Don’t short sell your business

Beyond the issue of concision, remember that the reason you’re writing code is to produce some kind of product or service. That product exists in some kind of category:

Messaging

Finance

Transportation

A/V Entertainment

Social Media

etc.

The reason these categories are differentiated is because each category represents a unique value proposition, targeted to a unique customer base, providing unique features, meeting unique expectations, and possibly leveraging unique technology.

It is rare that a developer even acknowledges his/her business when asking a question, and it is equally rare that a developer acknowledges his/her business when answering a question. This means social media developers may be utilizing patterns and architectures that were engineered for the transportation industry. Is that likely to be a good idea, in general?

Remember that you’re building something for your company, your product, and your customers. The business rules and relationships within your product, company, and industry are far more important then whether or not you force a Redux store into your app!

Moving forward with Flutter

Pointing out mistakes and confusion isn’t enough to help you avoid those mistakes and confusion, so let’s talk about how you might approach the quagmire of “state management” in Flutter.

Learn Flutter’s boundaries

I try to always point out in my Flutter presentations that Flutter isn’t an application framework, it’s a portable UI toolkit.

You build user interfaces in Flutter, not features. Therefore, it is critical that you understand where Flutter ends and your application begins.

Flutter consists, primarily, of a widget tree. That’s pretty much it. Flutter also brings along method channels to have conversations with Java/Kotlin/Obj-C/Swift, but that’s just a side effect of Flutter using Dart — those communication channels are not a fundamental feature of Flutter.

When you want to use Flutter for a screen or an app, you display a Flutter widget tree. Within Flutter, you compose existing widgets in this tree, you create custom widgets and compose them in this tree, you rebuild this tree whenever you want the pixels to change, and that’s pretty much all Flutter is meant to do. Beyond the widget tree, you should do whatever you need to do to implement the features that are unique to your app.

The one question that arises from this revelation is how a developer can get info into this widget tree, and how to get events out of the tree. Fortunately, Flutter provides some tools to help you at the boundary.

Learn Flutter’s tools at the boundary

When it comes to injecting information into a Flutter widget tree, developers are always welcome to send values into the top-level widget and then pass those values down the tree as desired. However, this approach is tedious, easy to screw up, and tends to couple things that otherwise would be independent.

InheritedWidget is one tool that Flutter provides to help with this issue of hydrating the widget tree. InheritedWidgets allow widgets lower in the tree to look up the tree, get a reference to an ancestor, and also to rebuild itself whenever that ancestor changes. Theme.of() and Navigator.of() are examples of InheritedWidgets.

InheritedModel is another flavor of InheritedWidget, but InheritedModel allows other widgets to only rebuild when a particular “aspect” of the data in the InheritedModel changes. This is primarily a performance optimization.

StreamBuilder is a widget that you can place in your widget tree that rebuilds itself every time an object is received in a stream.

When it comes time to getting information out of your widget tree, you’ll typically start with a GestureDetector, button, textfield or some other widget that recognizes user interaction. This represents the event which should trigger some behavior in your code. These widgets all take callback functions that can do anything you want.

Within a callback function, you may choose to invoke a method on an object that you’re holding within your widget. Or you might statically retrieve a singleton and invoke a method on it. Or you might grab a reference to an object by using an InheritedWidget (as mentioned above) and invoke a method on it. Whichever path you choose, the steps tend to be the same:

Register for user input with a callback. The callback is invoked. Retrieve an instance of a regular Dart object that is part of your application behavior. Call the method on that object that you want to run in response to the user’s input.

With these boundary tools at your disposal, you can now decide for yourself whether you want to implement Redux, BLoC, a data model, a domain model, a hexagonal architecture, or something completely bespoke.

Learn why Redux and BLoC exist

Developers are quick to jump on the Redux and BLoC bandwagons. They really do spread “virally.” There is nothing wrong with either of these paradigms, nor will there be anything wrong with the next paradigm that everyone jumps on. The problem is the decision process (or lack thereof) for using these paradigms.

Did you know that Redux was initially nothing more than a way to implement time travel in JavaScript?

Of course, Redux is more than just an experiment, today, but history and context are important.

How about the BLoC pattern?

The AdWords team at Google wanted to use Flutter for their mobile apps. The team also wanted to share business logic with their AngularDart web apps. The AdWords team came up with the concept of business logic components (BLoCs) to solve this problem. They presented BLoCs publicly in early 2018

Later in 2018, Matt and Filip from Flutter’s developer relations team wanted to provide Flutter developers with some inspiration for how they might integrate business logic with their Flutter widget tree. Matt and Filip looked at what various teams within Google were doing to solve this problem and they discovered BLoCs. They then presented BLoCs at I/O 2018 as a concrete example for how developers might choose to integrate business rules with Flutter widgets.

This pattern did not emerge from some Stanford research lab, nor is it baked into Flutter. The BLoC pattern is just one approach of many, but because it was presented at a major Google event, it seems to have been enshrined as some kind of official Flutter “state management” solution that everyone should learn and use. But now you know better!

So choose what you’d like. Redux, BLoC, data models, domain models, hexagonal architecture, etc. But make sure you know why you’re using it, and make sure you know where Flutter ends and your application begins. The real issue with all of these questions about Flutter and “state management” is that they indicate that most developers don’t understand Flutter’s widget tree well enough to answer this for themselves. When you are truly comfortable with moving information into and out of a Flutter widget tree, this question will become boring and mostly irrelevant. You’ll wonder why you ever asked it.