An easy to understand implementation of reactive values and objects

Inspired by GetX, observable_ish, and similar packages

pub package codecov checks popularity likes pub points

Features

ClassUse-case
RxValueA reactive value
RxObjectA reactive object
RxListA reactive list
RxMapA reactive map
RxSetA reactive set
RxCompositeA composite of Rx objects
RxCompositeListA composite version of RxList
RxCompositeMapA composite version of RxMap
RxCompositeSetA composite version of RxSet

There are convenience typedefs for RxBool, RxInt, RxDouble, and RxString

See fast_rx_flutter for Flutter-specific components

Usage

import 'package:fast_rx/fast_rx.dart';

void example() {
  // ...

  final count = 0.rx;

  // ...

  // ignore: avoid_print
  count.stream.listen(print);

  // ...

  // Will print the value
  count.value = 1;

  final list = <int>[].rx;
  // Will only notify after the run block completes
  list.run(() {
    list.add(1);
    list.add(2);
  });
}

RxObject

RxObject can be used to create reactive objects of classes outside of your control. If an object is within your control, consider making fields reactive instead.

import 'package:fast_rx/fast_rx.dart';

class Tuple<T1, T2> {
  T1 item1;
  T2 item2;

  Tuple(this.item1, this.item2);

  Tuple.from(Tuple<T1, T2> other) : this(other.item1, other.item2);

  @override
  operator ==(Object other) =>
      other is Tuple<T1, T2> && other.item1 == item1 && other.item2 == item2;

  @override
  int get hashCode => Object.hash(item1, item2);
}

class RxTuple<T1, T2> extends RxObject<Tuple<T1, T2>> implements Tuple<T1, T2> {
  RxTuple(super.value);

  @override
  T1 get item1 => value.item1;

  @override
  set item1(T1 value) => notifyIfChanged(() => unregisteredValue.item1 = value);

  @override
  T2 get item2 => value.item2;

  @override
  set item2(T2 value) => notifyIfChanged(() => unregisteredValue.item2 = value);

  @override
  Tuple<T1, T2> copyValue() => Tuple.from(unregisteredValue);

  @override
  bool shouldNotify(Tuple<T1, T2> oldValue) => oldValue != unregisteredValue;
}

extension RxTupleExtension<T1, T2> on Tuple<T1, T2> {
  RxTuple<T1, T2> get rx => RxTuple<T1, T2>(this);
}

RxComposite

An RxComposite is an Rx that contains other Rx objects, and notifies with them.

Create and use composite versions of RxIterables:

import 'package:fast_rx/fast_rx.dart';

void example() {
  final compositeList = [0.rx].rx.composite;
  final compositeMap = {0: 1.rx}.rx.composite;
  final compositeSet = {0.rx}.rx.composite;

  // All of these will cause their parent to notify
  compositeList[0].value = 1;
  compositeMap[0]!.value = 1;
  compositeSet.first.value = 1;
}

Custom RxComposite:

import 'package:fast_rx/fast_rx.dart';

class Composite extends RxComposite {
  final a = 1.rx;
  final b = 2.rx;
  final c = 3.rx;

  Composite() {
    // Register all rx fields so that this object notifies with them
    addRx(a);
    addRx(b);
    addRx(c);
  }
}

Testing custom Rx

Custom Rx objects can be tested for valid registration and notifications using fast_rx_test.

Additional information

See fast_ui for more information

Libraries

fast_rx