ReactiveStatelessWidget class Null safety

Use it instead of StatelessWidget to make the hole sub tree reactive.

Any state consumed in any widget child of the widget where the ReactiveStatelessWidget will be registered.

The list of registered states are updated for each rebuild. And any non used state will be removed from the list of subscribers.


class ViewModel {
  // Inject a reactive state of type int.
  // Works for all primitives, List, Map and Set
  final counter1 = 0.inj();

  // For non primitives and for more options
  final counter2 = RM.inject<Counter>(
    () => Counter(0),
    // State will be redone and undone
    undoStackLength: 8,
    // Build-in logger
    debugPrintWhenNotifiedPreMessage: 'counter2',

  //A getter that uses the state of the injected counters
  int get sum => counter1.state + counter2.state.value;

  incrementCounter1() {

  incrementCounter2() {
    counter2.state = Counter(counter2.state.value + 1);
class CounterApp extends ReactiveStatelessWidget {
   const CounterApp();

    Widget build(BuildContext context) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          Text('🏁 Result: ${viewModel.sum}'), // Will be updated when sum changes

  // Child 1 - Plain StatelessWidget
  class Counter1View extends StatelessWidget {
    const Counter1View({Key? key}) : super(key: key);

    Widget build(BuildContext context) {
      return Column(
        children: [
            child: const Text('🏎️ Counter1 ++'),
            onPressed: () => viewModel.incrementCounter1(),
          // Listen to the state from parent
          Text('Counter1 value: ${viewModel.counter1.state}'),

  // Child 2 - Plain StatelessWidget
  class Counter2View extends StatelessWidget {
    const Counter2View({Key? key}) : super(key: key);

    Widget build(BuildContext context) {
      return Column(
        children: [
            child: const Text('🏎️ Counter2 ++'),
            onPressed: () => viewModel.incrementCounter2(),
            child: const Text('⏱️ Undo'),
            onPressed: () => viewModel.counter2.undoState(),
          Text('Counter2 value: ${viewModel.counter2.state.value}'),

Important Notes:

ReactiveStatelessWidget offers the following hooks: ReactiveStatelessWidget.didMountWidget, ReactiveStatelessWidget.didUnmountWidget ReactiveStatelessWidget.didAddObserverForDebug ReactiveStatelessWidget.shouldRebuildWidget




ReactiveStatelessWidget({Key? key})


hashCode int
The hash code for this object. [...]
@nonVirtual, read-only, inherited
key Key?
Controls how one widget replaces another widget in the tree. [...]
final, inherited
runtimeType Type
A representation of the runtime type of the object.
read-only, inherited


build(BuildContext context) Widget
createElement() StatefulElement
Creates a StatefulElement to manage this widget's location in the tree. [...]
createState() → _ReactiveStatelessWidgetState
Creates the mutable state for this widget at a given location in the tree. [...]
debugDescribeChildren() List<DiagnosticsNode>
Returns a list of DiagnosticsNode objects describing this node's children. [...]
@protected, inherited
debugFillProperties(DiagnosticPropertiesBuilder properties) → void
Add additional properties associated with the node. [...]
didAddObserverForDebug(List<InjectedBaseState> observers) → void
Called in debug mode only when an state is added to the list of listeners
didMountWidget() → void
Called when the widget is first inserted in the widget tree
didNotifyWidget(SnapState snap) → void
Called when the widget is notified to rebuild, it exposes the SnapState of the state that emits the notification
didUnmountWidget() → void
Called when the widget is removed from the widget tree
noSuchMethod(Invocation invocation) → dynamic
Invoked when a non-existent method or property is accessed. [...]
shouldRebuildWidget(SnapState oldSnap, SnapState currentSnap) bool
Condition on when to rebuild the widget, it exposes the old and the new SnapState of the the state that emits the notification.
toDiagnosticsNode({String? name, DiagnosticsTreeStyle? style}) DiagnosticsNode
Returns a debug representation of the object that is used by debugging tools and by DiagnosticsNode.toStringDeep. [...]
toString({DiagnosticLevel minLevel =}) String
A string representation of this object. [...]
toStringDeep({String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug}) String
Returns a string representation of this node and its descendants. [...]
toStringShallow({String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) String
Returns a one-line detailed description of the object. [...]
toStringShort() String
A short, textual description of this widget.


operator ==(Object other) bool
The equality operator. [...]
@nonVirtual, inherited