Easy
An easy Flutter state management that allows minimal rebuild of widgets and improves performance.
Getting Started
This package is available on pub.dev: package,
##HOW TO USE?
Add this to your package's pubspec.yaml file:
dependencies:
easy:
Import it:
import 'package:easy/easy.dart';
Add EasyManager and your state class to Main:
example:
void main() {
runApp(EasyManager(
bloc: [
Easy<AppBloc>(
builder: (context) => AppBloc(),
),
],
child: MyApp(),
));
}
Create your state class and extends EasyBloc overriding touch method:
class AppBloc extends EasyBloc {
int counter = 0;
@override
void touch() {
counter++;
super.touch();
}
}
With Easy, any variable you put into your EasyBloc class will be accessible through the Widget Store.
And to call any function or method within your EasyBloc class you just need to call "EasyState.of
You can call "EasyState.of
Example:
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
//
final bloc = EasyState.of<AppBloc>(context, listen: false);
return Scaffold(
floatingActionButton: FloatingActionButton(
//Run the "touch" method and everything in it in your EasyBloc class will be instantly executed.
child: Icon(Icons.add), onPressed: () => bloc.touch()),
body: Center(
// Get the value of any variable within your EasyBloc class using the "Store" widget.
child: Store<AppBloc>(
builder: (context, value, child) => Text(
"${value.counter}",
style: TextStyle(fontSize: 50),
)),
),
);
}
}
And that's all, when you click on the FloatingActionButton the value will be incremented automatically. Only the Text will be redone, all other widgets will remain intact. This allows for considerable performance gain when you have heavy widgets (such as videos, gifs, maps) in the tree.
In addition to improving performance, clearing code that will separate the business logic part of the UI (following the BLoC standard), EasyProvider works with Singletons, so you can call the Widget Store from anywhere in your code, even on another screen, being able to read and change it from anywhere without any boilerplate code!
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final bloc = EasyState.of<AppBloc>(context, listen: false);
print("rebuild");
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add), onPressed: () => bloc.touch()),
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
},
child: Text('Go to Next Screen!'),
),
Store<AppBloc>(
builder: (context, value, child) => Text(
"${value.counter}",
style: TextStyle(fontSize: 50),
)),
],
),
),
),
);
}
}
class SecondRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
final bloc = EasyState.of<AppBloc>(context, listen: false);
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
heroTag: "increment second route",
onPressed: () => bloc.touch(),
),
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Store<AppBloc>(
builder: (context, counter, child) => Text(
"${counter.counter}",
style: TextStyle(fontSize: 50),
)),
RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
],
),
),
);
}
}
You can amazingly increment the counter number of both screens! That is all? No. You in addition to performing functions you can inject values from anywhere in your code.
This is made possible by the injection methods incorporated in Easy. Easy natively accepts Strings, int, Map, List, bool, double and dynamic for injection. Simply override any inject method on your EasyBloc.
Example with int:
class AppBloc extends EasyBloc {
int counter = 0;
@override
void injectInt(int integer) {
counter = integer;
super.injectInt(integer);
}
@override
void touch() {
counter++;
super.touch();
}
}
Now, inject any value via parameter, and the counter will be updated automatically.
Note that if you click increment, it will increment the value already injected. This would not be possible for example, natively with Streams, unless you used RxDart's BehaviourSubject.
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final bloc = EasyState.of<AppBloc>(context, listen: false);
print("rebuild");
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add), onPressed: () => bloc.touch()),
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
},
child: Text('Go to Next Screen!'),
),
Store<AppBloc>(
builder: (context, value, child) => Text(
"${value.counter}",
style: TextStyle(fontSize: 50),
)),
RaisedButton(
onPressed: () {
bloc.injectInt(333);
},
child: Text('inject 333 on counter'),
),
],
),
),
),
);
}
}
Didn't like my comment above? Keep calm, I also love Streams, inclusive, you can use Streams with this package if you prefer.
class AppBloc extends EasyBloc {
int counter = 0;
final _counterController = StreamController<int>();
// can work with rxDart like:
// final _counterController = BehaviouSubject<int>();
get counterOut => _counterController.stream;
@override
void touch() {
counter++;
_counterController.sink.add(counter);
super.touch();
}
@override
void dispose() {
_counterController.close();
super.dispose();
}
}
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final bloc = EasyState.of<AppBloc>(context, listen: false);
print("rebuild");
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add), onPressed: () => bloc.touch()),
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
StreamBuilder<int>(
initialData: 0,
stream: bloc.counterOut,
builder: (context, snapshot) {
return Text(
"${snapshot.data}",
style: TextStyle(fontSize: 50),
);
}),
],
),
),
),
);
}
}
For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.
Libraries
Dart
- dart:ui
- Built-in types and core primitives for a Flutter application. [...]
- dart:async
- Support for asynchronous programming, with classes such as Future and Stream. [...]
- dart:collection
- Classes and utilities that supplement the collection support in dart:core. [...]
- dart:convert
- Encoders and decoders for converting between different data representations, including JSON and UTF-8. [...]
- dart:core
- Built-in types, collections, and other core functionality for every Dart program. [...]
- dart:developer
- Interact with developer tools such as the debugger and inspector. [...]
- dart:math
- Mathematical constants and functions, plus a random number generator. [...]
- dart:typed_data
- Lists that efficiently handle fixed sized data (for example, unsigned 8 byte integers) and SIMD numeric types. [...]
- dart:io
- File, socket, HTTP, and other I/O support for non-web applications. [...]
- dart:isolate
- Concurrent programming using isolates: independent workers that are similar to threads but don't share memory, communicating only via messages. [...]