Basic State Management in Google Flutter

How I Met Google Flutter

It was an ordinary programming day for me. One of my friend sent a question to our developers chat group. He asked whether anyone has tried Google Flutter. He wanted to know the comparison between React Native and Google Flutter.
The question tickled me a bit. I never heard about Google Flutter. Does it ‘deserve’ to be compared with React Native just like AngularJS compared with ReactJS?

I must admit. I’m a React fanboy. I’ve been using ReactJS for around 2 years. I also code React Native. But don’t get me wrong. I was so crazy for AngularJS before. I was an AngularJS developer for around a year. Then I moved to a new company that used ReactJS. And the rest is history…

TL;DR I eager myself to try Google Flutter.

Google Flutter is a new platform for developing Android and iOS apps from a single codebase, written in Dart. Moving to a new development stack makes me aware of my priorities, at least to make a simple application, which is: STATE MANAGEMENT. It led me to 3 problems:

  1. How to pass an app’s state down to the widgets tree
  2. How to rebuild widgets after updating the app’s state
  3. How to navigate between screens and keep the state synced

THE EXECUTION

By default, flutter will create main.dart. It’s where the app runs. Since I wanted to create a navigation between two screens, I created 2 additional files: MyHomePage.dart and MySecondPage.dart.

The purpose of this application is to let user:

  • Increment the counter in MyHomePage.
  • Navigate to MySecondPage.
  • Decrement the counter in MySecondPage.

While this seems to be easy, I still had to find a way to keep the counter between MyHomePage and MySecondPage synced.

Take the counter as 0. If in MyHomePage user increments the counter 2 times, then when user navigates to MySecondPage, the counter must show 2.

Meanwhile, if in MySecondPage user decrements the counter 2 times, then when user navigates to MyHomePage, the counter must show 0.

This is called a state management.

I learned that Google Flutter has setState() mechanism that React also has. This helps me to find out the solution faster.

In my main.dart file:

import 'package:flutter/material.dart';
import 'package:flutter_redux_example/screens/MyHomePage.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {

@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
  int counter;
  @override
void initState() {
super.initState();
counter = counter ?? 0;
}
  void _decrementCounter(_) {
setState(() {
counter--;
print('decrement: $counter');
});
}

void _incrementCounter(_) {
setState(() {
counter++;
print('increment: $counter');
});
}
  @override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(
title: 'My Home Page',
counter: counter,
decrementCounter: _decrementCounter,
incrementCounter: _incrementCounter,
),
);
}
}

From above code, you see there are _decrementCounter() and _incrementCounter(). They are responsible to manipulate the counter’s value. Then I passed them to MyHomePage constructor.

In my MyHomePage.dart file:

import 'package:flutter/material.dart';
import 'package:flutter_redux_example/screens/MySecondPage.dart';
class MyHomePage extends StatefulWidget {
  MyHomePage({
Key key,
this.title,
this.counter,
this.decrementCounter,
this.incrementCounter
}) : super(key: key);
  final String title;
final int counter;
final ValueChanged<void> decrementCounter;
final ValueChanged<void> incrementCounter;
  @override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  void _onPressed() {
widget.incrementCounter(null);
}
  @override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text('You have pushed the button this many times:'),
new Text(
widget.counter.toString(),
style: Theme.of(context).textTheme.display1,
),
new RaisedButton(
child: new Text('Next Screen'),
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new MySecondPage(
widget.decrementCounter,
title: 'My Second Page',
counter: widget.counter,
),
),
);
},
)
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _onPressed,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
);
}
}

From above code, you see that I passed down decrementCounter() to MySecondPage constructor.

In my MySecondPage.dart file:

import 'package:flutter/material.dart';

class MySecondPage extends StatefulWidget {
  MySecondPage(
this.decrementCounter,
{Key key, this.title, this.counter}
): super(key: key);
  final String title;
final int counter;
final ValueChanged<void> decrementCounter;
  @override
_MySecondPageState createState() => new _MySecondPageState();
}
class _MySecondPageState extends State<MySecondPage> {
  void onPressed() {
widget.decrementCounter(null);
}
  @override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text('You have pushed the button this many times :'),
new Text(
super.widget.counter.toString(),
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: onPressed,
tooltip: 'Decrement',
child: new Icon(Icons.indeterminate_check_box),
backgroundColor: Colors.red),
);
}
}

You can find the demo here:

http://res.cloudinary.com/dg5tnpiuu/video/upload/v1525657732/Flutter_1_c470ku.mp4


CONCLUSION

Coming from React background, it’s not extremely difficult to play with basic state management in Google Flutter. The approach kinda looks similar: there is a setState() mechanism to update the view. The StatefulWidget and StatelessWidget concept looks like Component and PureComponent for me. And Google Flutter called them Widget while React called them Component.

So, basically, the main problem is with the programming language that Google Flutter’s using. Since it’s using Dart, I’ve to get used to the syntax and the paradigm that Dart embraces. So far, it’s not extremely difficult. For me, Dart looks like Java and Javascript having a baby.

In this post, I managed to solve the 3 problems I mentioned earlier:

  1. Pass an app’s state down to the widgets tree ✅
  2. Rebuild widgets after updating the app’s state ✅
  3. Navigate between screens and keep the state synced ✅

Remember, this is only a very simple application. Things will be more complicated for larger application. Imagine if you have to pass down the variable through all widgets of the application. It will be troublesome!

In React environment, I use Redux to manage the application state. I learned that Redux is also applicable in Google Flutter. In fact, I’ve successfully implemented Redux to Google Flutter application. Let’s see if I can manage to create another post about it.