Simple Flutter State Management

Tafadzwa L Nyamukapa
The Startup
Published in
5 min readAug 17, 2020

--

A Flutter package reactivestore which helps developers in managing the state of their apps and creating reactive components/widgets with less boiler plate code. Check it in pub.dev here.

Flutter state management on a dialog using reactivestore package

Getting Started

This package was inspired by the medium post i wrote here on Dialog State Management in Flutter — using Providers and Change Notifiers.

Usage

Example

To use this package :

dependencies:
flutter:
sdk:flutter
reactivestore:

How to Use

The reactivestore package has two classes :

  1. ReactiveStore
  2. UpdateUI

The ReactiveStore class is an ancestor class that provides an instance of changes to all its descendants. The ReactiveStore takes a child widget as the root ancestor widget see example below.

In the example above all descendants of the MyHomePage will be monitored for changes in their states.

The UpdateUI is the Consumer Widget for those who are familiar with the provider package. The widget is used to update the UI of our application whenever there is a change in state in our application tree. The UpdateUI widget takes a builder function. The Builder function has three arguments :

new UpdateUI(
builder: (BuildContext, StoreModel, Widget)=>child
)

The BuildContext is the current context of your widget, StoreModel is the name of the store(you can give it any name) and the Widget is the child. See example below:

The Store ADT

The above example introduced us to the final piece of our reactivestore which is the StoreModel Abstract Data Type (ADT). The StoreModel is the store which stores the data. The StoreModel listens for changes in state in our app and notifies the Widgets wrapped by the UpdateUI widget. The StoreModel is essentially an Observable class.

The data in the store is accessed using the of method in the StoreModel . To access the data without necessarily changing the UI you use it with a listen parameter set to false as follows.

final model  = StoreModel(); //Instantiating the Observable StoreModel class
final x = model.of(context, false); //initialize an instance that access the data without rebuilding UI.

The StoreModel is a List implmented ADT with the following operations:

final obj = StoreModel(); //initializing the StoreModel

Imports

After installing the reactivestore package remember the imports

import 'package:reactivestore/model/store_model.dart';
import 'package:reactivestore/reactivestore.dart';

Example

See full example here

In this Example i will show you how you can easily manage the state of your app using a Dialog as a descendant class.

In the above snippet i have imported the reactivestore. I have wrapped the root MaterialApp with a ReactiveStore Widget.

In the above code notice how we are tracking for changes in state using the UpdateUI widget.

...
...
new Padding(
padding: EdgeInsets.all(10.0),
child: UpdateUI(
builder: (context,consumerModel,child)=>consumerModel.itemsList !=null?Text(
consumerModel.totalItems.toString(),
style: TextStyle(fontWeight: FontWeight.w500,fontSize: 25.0, color: Colors.green),):null,
),
),
...
...

The UpdateUI will rebuild whenever something is added to our store.

  • Nb The builder in UpdateUI takes three arguments(BuildContext, StoreModel, Widget). You can name the the StoreModel however you want as long as you are using the name to access the data in store. eg consumerModel as above.

In the above snipped notice how we are accessing the data using a list map conversion

new Text('\$ ${customerModel.itemsList[index]['salary'].toString()}.00',style: titleStyle,),

As described above remember to use the keyword itemsList to access the list data.

The result after the above implementation. Remember to comment out MyCustomDialog call in the floating action button since we haven't implemented it yet.

Fig show the look of the page after the above implementation.

Now we need to implement the MyCustomDialog in the floating action button.

Fig show the Dialog after the above implementation of code

The MyCustomDialog class is the descendant class of the ancestor ReactiveStore class Widget. Now lets take a look at the addCustomer method. The method will add our data into the store, in this case the name and salary. To access the data in our store you use the of method in the StoreModel. To access while notifying Widgets wrapped by the UpdateUI Widget we use the of method in the StoreModel with listen set to true. See code below:

To add data in the store you use the add method in the StoreModel. If you want to access the data without necessarily rebuilding the UI (i.e rebuilding widgets wrapped by UpdateUI Widget) you set the listen parameter to false or directly use the instance of the StoreModel. See code below:

final model  = StoreModel();
final access = model.of(context, false);
//these return the total number of items(items being Maps of data) in the store without rebuilding the UI
int items = model.itemsList.length;
int items2 = access.itemsList.length;
  • NB Directly using the StoreModel instance object to access operations in the StoreModel does not the rebuild UI you need to pass the context and listen using the of method.

remove Method

In the above method the _showAlertDialog in the MyHomePage in notice how the of method has its listen parameter set to true. This is such whenever we remove an data from our store we want to instantly rebuild the UI ie widgets wrapped by the UpdateUI class.

CONCLUSION

  1. Wrap ancestor widget with ReactiveStore Widget.
  2. Wrap descendant widget that you want to rebuild whenever there is a change in state with UpdateUI Widget
  3. To access data and make updates to the store while rebuilding UI use of method in StoreModel with listen set to true.
  4. To access data without rebuilding UI use:
    a) Directly use the instance of StoreModel e.g.
    final model = StoreModel();
    print(model.itemsList.length);
    b) Use of method with listen set to false eg
    final model = StoreModel();
    final access = model.of(context, false);
    print(access.add({‘name’:’John’, ‘age’:7}));

!!END

Pull Requests

I Welcome and i encourage all Pull Requests

Created and Maintained by

--

--

Tafadzwa L Nyamukapa
The Startup

Software Engineer with a huge passion for building software and explore new technologies. FinTech | CKA | Java | Django | AI | Js | System Architect | Cloud