RxDart for the smallest ... projects







Yesterday, my good friend said something like "I’m writing a simple offline application, I don’t need all these streams and streams." I was even confused, and then I thought that other encoders could share this error.







Below, literally in 50 lines, I will show by a well-known example that reactivity







a) this is not about offline / online

b) it is very simple

c) very good for simplifying almost any code







To my hasty critics

who rush into battle without thinking, considering that BlocProvider



is a provider , I recommend for general development to read the basic article first, the link to which is on the flutter_bloc page , on the first line of the description.







The well-known example "Counter" that is generated when creating a Flutter project is whipping boy A good starting point to demonstrate many practices.

So, it contains MyHomePage extends StatefulWidget



, the _incrementCounter



method for the increment command and setState



to redraw the entire widget hierarchy.







Add reactivity with the rxdart



library and a few simple steps:







Add the library to pubspec.yaml



 dependencies: ... rxdart: 0.22.2
      
      





Change the counter architecture and add event



 class _Counter { int _count; int get count => _count; _Counter(this._count) : this.onCounterUpd = BehaviorSubject<int>.seeded(_count); ///  . final BehaviorSubject<int> onCounterUpd; ///     ,   . Future incrementCounter() async { onCounterUpd.add(++_count); } } final _counter = _Counter(5);
      
      





Let's make the class StatelessWidget



 ///   " " class MyHomeRxPage extends StatelessWidget { final title; /// ! -     const MyHomeRxPage({Key key, this.title}) : super(key: key); ...
      
      





Wrap the display widget in StreamBuilder and change the call to the increment method



  StreamBuilder<int>( stream: _counter.onCounterUpd, builder: (context, snapshot) { return Text( '${snapshot.data}', style: Theme.of(context).textTheme.display1, ); }), ... floatingActionButton: FloatingActionButton( onPressed: _counter.incrementCounter, ...
      
      





That's all. It totally looks like this







 import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:rxdart/rxdart.dart'; class _Counter { int _count; int get count => _count; _Counter(this._count) : this.onCounterUpd = BehaviorSubject<int>.seeded(_count); ///  . final BehaviorSubject<int> onCounterUpd; ///     ,   . Future incrementCounter() async { onCounterUpd.add(++_count); } } final _counter = _Counter(5); /// class MyHomeRxPage extends StatelessWidget { final title; /// ! -     const MyHomeRxPage({Key key, this.title}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. title: Text(title), ), body: Center( // Center is a layout widget. It takes a single child and positions it // in the middle of the parent. child: Column( // Column is also a layout widget. It takes a list of children and // arranges them vertically. By default, it sizes itself to fit its // children horizontally, and tries to be as tall as its parent. // // Invoke "debug painting" (press "p" in the console, choose the // "Toggle Debug Paint" action from the Flutter Inspector in Android // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) // to see the wireframe for each widget. // // Column has various properties to control how it sizes itself and // how it positions its children. Here we use mainAxisAlignment to // center the children vertically; the main axis here is the vertical // axis because Columns are vertical (the cross axis would be // horizontal). mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ StreamBuilder<int>( stream: _counter.onCounterUpd, builder: (context, snapshot) { return Text( 'You have pushed the button ${snapshot.data} times:', ); }), // Text( // 'You have pushed the button this many times:', // ), /// 6. StreamBuilder<int>( stream: _counter.onCounterUpd, builder: (context, snapshot) { return Text( '${snapshot.data}', style: Theme.of(context).textTheme.display1, ); }), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _counter.incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); } }
      
      





Now the code is reactive, concise, saved from unnecessary redrawings, and easily extensible.

For example, if at the time of changing the counter you need to change the text of another widget, just do this:







  StreamBuilder<int>( stream: onCounterUpd, builder: (context, snapshot) { return Text( 'You have pushed the button ${snapshot.data} times:', ); }), // Text( // 'You have pushed the button this many times:', // ),
      
      





and voila!







For comparison, try to do the same with InheritedWidget, or another pattern.







So, hopefully, I showed that









Example code (branch iter_0004_rxdart



)







Edited an hour later

In vain did it too simple, got clicks for "global variables" and a wrong understanding of BehaviorSubject



initialization, fixed








All Articles