If you are doing anything in mobile development these days, you may have heard of this little thing called Flutter. It’s an awesome mobile UI framework that challenges you to think of app development like game development, where the runtime is shipped with the application allowing for a fully customizable experience without forsaking performance.

While researching how to build apps using Flutter, you may have come across setState and redux as the two most popular patterns for managing application state. Though they both have their place, there is a wide gap between the simplicity of setState and the flexibility of redux.

What’s wrong with setState?

To be clear, there is nothing wrong with using setState . This method of updating widget state is one of the most powerful features of both Flutter and React. You can read here about how you can use top-down data flow to manage state in a React application effectively. The pattern applies just as well to Flutter.

That said, if you are familiar with React then you have encountered the pains of “prop drilling”. For the uninitiated, it is the process of passing props through components that don’t care about the data just so you can send it down to components that do care. The problem is magnified when restructuring components, making maintenance a nightmare and you could also experience some performance degradation by re-rendering parts of the widget tree for the sake of one widget.

What’s wrong with Redux?

As with setState , there is nothing wrong with redux. It is a perfectly fine pattern for managing as much of your application’s state as you desire.

That said, using redux is not without its cons, chief of which being the complexity that it adds when it may not be necessary. As good citizens, we

Should not over-optimize.

Should not use patterns or libraries because they’re popular.

Redux, however awesome it has been for frontend development, is no exception.

Getting setState simplicity with State Management

Being a big proponent of React, I am a big fan of the growing trend of libraries in the community that utilize its new Context API to hit a sweet spot in state management. While searching for a similar pattern, I came across scoped_model.

If you’re interested in managing state in your flutter app I strongly encourage the use of Scoped Models. Note this currently isn’t the ‘normal’ way of managing state in a flutter app but we’ve found it extremely useful. Personally, I take the stance that you should use StatefulWidgets as little as possible. Scoped Models help with that immensely.

Just like unstated takes advantages of patterns that already exist in React and context, scoped_model builds on patterns you’re already familiar with if you use setState .

Overview

scoped_model builds upon three main ideas:

1. Model

Conceptually, a Model is very similar to a redux store. It’s a widget-like class that only contains the state-related bits.

CounterModel extends Model

2. ScopedModel

The ScopedModel contains the state Model , providing it to all widgets that request it. This is similar to the Provider in unstated.

Create ScopedModel at the top level of the app

3. ScopedModelDescendant

The ScopedModelDescendant widget allows you to pass state from the Model to your widget. State changes will trigger re-rendering and you can call methods on the Model . This is very similar to the Subscribe component in unstated.

ScopedModelDescendant accepts a builder function that passes in the model.

Adding multiple Containers to a widget

After looking at the API, one of the first questions I had was How do I add multiple models to a widget?

This is fairly trivial using mixins. Let’s rewrite the previous example, adding the ability to decrement and reset the count:

We can then replace our creation of CounterModel with MainModel at the root of our application

Replace CounterModel with MainModel

Finally, we can complete our example using multiple models

Build functions can access all of the MainModel props

You may be thinking

Why doesn’t he just put all of these methods together to form one logical model?

You are right in your assessment that this example separation does not make much sense. Think of this as more of a demonstration of the capability.

In reality, you should be combining models that represent different types of state (CounterState, AuthState, ProfileState, etc.).

Asynchronous operations

Because of the simplicity of the model, async operations become a snooze fest. Once the state changes, firing notifyListeners essentially operates just like setState .

Conclusion

In the beginning of this article, I mention that there is nothing wrong with using setState or redux for state management and I would like to reiterate that statement. This article is more about the effort to fill the gap between the two.

Similar to how unstated is an evolution of state management in React, scoped_model is an evolution in Flutter. Like unstated, it reduces complexity and stays within the boundaries of Flutter.

When thinking of state management, scoped_model is worth consideration next to setState and redux, especially when you desire something more powerful than setState but without the baggage.

If you would like to see the full working demo for this article, you can find it here.