Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid repetition in BLoCs and RxDart

Tags:

hopefully I can make myself clear.

After video and tutorials, I found this way to have some widgets to input data to the bloc (valueSetting) and some others to get this data (value).

What I am asking is if there is a better way (there has to be..). I want to avoid the need to have 4 variables for just 1 real value shared between widgets.

import 'dart:async';

import 'package:rxdart/subjects.dart';

class BlocExample {
  final _valueSettingController = StreamController<bool>();

  // object use by widget to push data
  Sink<bool> get valueSetting => _valueSettingController.sink;

  final _value = BehaviorSubject<bool>(seedValue: false);

  // object used by widget to get data
  Stream<bool> get value => _value.stream;

  BlocExample() {
    _valueSettingController.stream.listen(_value.add);
  }

  void dispose() {
    _value.close();
    _valueSettingController.close();
  }
}
like image 451
vmihalachi Avatar asked Aug 13 '18 15:08

vmihalachi


People also ask

When should I use RxDart?

The extension methods provided by RxDart can be used on any Stream . They convert a source Stream into a new Stream with additional capabilities, such as buffering or throttling events.

Is RxDart state management?

There will be an app that provides a list of universities that can be queried by their country. There we are using: RxDart for data streams and state management.


2 Answers

First of, let me say that you can remove the private variables by using a custom factory constructor. Here's an example:

class MyBloc {
  final Sink<bool> input;
  final Stream<bool> output;
  final VoidCallback _dispose;

  MyBloc._({this.input, this.output, VoidCallback dispose}) : _dispose = dispose;

  factory MyBloc() {
    final mainController = BehaviorSubject(seedValue: false);
    return MyBloc._(
      input: mainController.sink,
      output: mainController.stream,
      dispose: () {
        mainController.close();
      },
    );
  }

  void dispose() {
    _dispose();
  }
}

Secondly, the problem you're trying to solve is actually not a problem. While it seems at first that there's a lot of duplicates; in reality they serve different purposes.

In many situations, your Stream will be more than just _controller.stream. For example, for whatever reason you may want to transform the value before exposing it:

final mainController = BehaviorSubject(seedValue: false);

final Stream<bool> output = mainController.map((foo) => !foo);

This code makes that the output stream reverses the value of everything passed to mainController.sink

But in my situation this is not the case. So why 3 variables that point to the same thing?

The fact that in your situation, your controller is both the sink and stream without transformation is an implementation detail and may be subject to changes.

By exposing Sink/Stream as done before, you actually abstract this implementation detail. So that in the future if your stream needs custom operations; no change will be required by your UI.

This is not necessary. But recommended.

like image 198
Rémi Rousselet Avatar answered Sep 28 '22 19:09

Rémi Rousselet


You can do something like this :)

  enum STREAM_GROUP {
    TYPE1,TYPE2,TYPE3
  }

  class BlocExample {

        Map<STREAM_GROUP, StreamController<bool>> groups = new Map();

        Stream<bool> getValue(STREAM_GROUP type){
          return groups[type].stream;
        }
        Sink<bool> getValueSetting(STREAM_GROUP type){
          return groups[type].sink;
        }

        BlocExample() {
          groups[STREAM_GROUP.TYPE1] = StreamController<bool>();
          groups[STREAM_GROUP.TYPE2] = StreamController<bool>();
          groups[STREAM_GROUP.TYPE3] = StreamController<bool>();

          groups.forEach((groupType, streamController){
              final currentValue = BehaviorSubject<bool>(seedValue: false);
              streamController.stream.listen(currentValue.add);
          });


        }

        void dispose() {
           groups.forEach((groupType, streamController){
              streamController.close();
          });
        }
      }
like image 30
diegoveloper Avatar answered Sep 28 '22 18:09

diegoveloper