Flutter Super State: Simple State Management for Flutter
Charles Crete
Posted on May 7, 2020
flutter_super_state is a new state management library for Flutter which:
- Is simple to use. Simply create modules
- Supports
async
actions easily - Can easily be integrated with Flutter
Today we will take a look at creating a simple application with a mock authentication and a counter.
Concepts
Super State has 2 main objects:
-
Store
: Which holds all of your modules -
StoreModule
: Which you can extend to implement modules
Let's take a look at a simple module:
import 'package:flutter_super_state/flutter_super_state.dart';
// Modules extend `StoreModule`
class CounterModule extends StoreModule {
// Read only property, to avoid accidentally setting `counter` without calling `setState`
int get counter => _counter;
var _counter = 0;
// This automatically registers your module to your store
CounterModule(Store store): super(store);
// Synchronous actions
void increment() {
setState(() {
_counter++;
});
}
void decrement() {
setState(() {
_counter--;
});
}
// Asynchronous action
Future<void> reset() async {
// Fake async delay
await Future.delayed(Duration(milliseconds: 10));
setState(() {
_counter = 0;
});
}
}
A store is easy to setup, here's an example:
import 'package:flutter_super_state/flutter_super_state.dart';
final store = Store();
// Register modules. Order does not matter. You should register all modules on initialization
CounterModule(store);
You can then call get modules from the store and call actions:
store.getModule<CounterModule>().increment();
await store.getModule<CounterModule>().reset();
For Flutter integration, the package provides for following widgets:
-
StoreProvider
: Provides the store to all children in sub-tree -
ModuleBuilder
: Access a module inside the Flutter widget tree (is updated when module callssetState
) -
StoreBuilder
: Access the store inside the Flutter widget tree (is updated when any module callssetState
)
Example
Let's start by creating a new project using flutter create super_state_example
and adding the package to pubspec.yaml
:
dependencies:
flutter_super_state: # Optionally put latest version from pub.dev
Next, let's clear your main.dart
, and place our CounterModule
from above inside lib/src/store/counter.dart
. Let's create our second module, AuthModule
(inside lib/src/store/auth.dart
):
import 'package:flutter_super_state/flutter_super_state.dart';
import 'package:state_test/src/store/counter.dart';
class AuthModule extends StoreModule {
int get isLoggedIn => isLoggedIn;
var _isLoggedIn = false;
AuthModule(Store store) : super(store);
Future<void> login() async {
// Do network request...
await Future.delayed(Duration(milliseconds: 100));
setState(() {
_isLoggedIn = true;
});
}
Future<void> logout() async {
// Do network request...
await Future.delayed(Duration(milliseconds: 100));
setState(() {
_isLoggedIn = true;
});
// Call action in other module
await store.getModule<CounterModule>().reset();
}
}
We should have our modules complete! Next, let's setup 2 screens (LoginScreen
and CounterScreen
):
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Login"),
),
body: Center(
// Login button
child: ModuleBuilder<AuthModule>(
builder: (context, authModule) {
return RaisedButton(
child: Text("Login"),
onPressed: () async {
// Call action
await authModule.login();
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => CounterScreen()),
);
},
);
},
),
),
);
}
}
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Counter"),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// Our counter module
ModuleBuilder<CounterModule>(
builder: (context, counterModule) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text("Increment"),
onPressed: () => counterModule.increment(),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(counterModule.counter.toString()),
),
RaisedButton(
child: Text("Decrement"),
onPressed: () => counterModule.decrement(),
),
],
);
},
),
// Logout button
ModuleBuilder<AuthModule>(
builder: (context, authModule) {
return RaisedButton(
child: Text("Logout"),
onPressed: () async {
await authModule.logout();
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => LoginScreen()),
);
},
);
},
),
],
),
);
}
}
Next, let's setup our main.dart
:
void main() {
// Create the store
final store = Store();
// Register modules
CounterModule(store);
AuthModule(store);
// Provide store to whole application
runApp(StoreProvider(
store: store,
child: ExampleApp(),
));
}
class ExampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: LoginScreen(),
);
}
}
And we are done! Let's check it out:
You can view the whole project here.
Thanks for reading, don't forget to check out the package!
Posted on May 7, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.