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



Source: https://habr.com/ru/post/474968/


All Articles