Flutter Tutorial

Flutter Intermediate Lesson 55 of 135 2 min read

states_rebuilder in Flutter: Reactive State with RM.inject

Learn states_rebuilder with a simple counter and async example: RM.inject, OnReactive, OnBuilder, side effects and async loading, for beginners.

On this page

states_rebuilder is a reactive state management package. You inject a piece of state once with RM.inject, change it with .state, and widgets that read it inside OnReactive rebuild automatically. It also handles async state, dependency injection and navigation.

The package is not available in the online editor, so run the examples in your own project.

Install

flutter pub add states_rebuilder

The counter

import 'package:flutter/material.dart';
import 'package:states_rebuilder/states_rebuilder.dart';

// Injected once, at the top level.
final counter = RM.inject<int>(() => 0);

void main() => runApp(const MaterialApp(home: CounterPage()));

class CounterPage extends StatelessWidget {
  const CounterPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('states_rebuilder')),
      body: Center(
        child: OnReactive(
          () => Text('${counter.state}', style: const TextStyle(fontSize: 48)),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counter.state++,
        child: const Icon(Icons.add),
      ),
    );
  }
}

OnReactive works out which injected states its builder read, and rebuilds when any of them changes.

A model class

class Cart {
  const Cart(this.items);
  final List<String> items;
  Cart add(String item) => Cart([...items, item]);
}

final cart = RM.inject<Cart>(() => const Cart([]));

// Change it by assigning a new state:
cart.state = cart.state.add('Apple');

// Read it:
OnReactive(() => Text('${cart.state.items.length} items'));

Async state

final weather = RM.injectFuture<String>(
  () async {
    await Future.delayed(const Duration(seconds: 1));
    return 'Sunny, 24°C';
  },
);

OnBuilder.all(
  listenTo: weather,
  onWaiting: () => const CircularProgressIndicator(),
  onError: (error, refresh) => TextButton(onPressed: refresh, child: const Text('Retry')),
  onData: (data) => Text(data),
);

OnBuilder.all makes you handle the loading, error and data cases, so none is forgotten.

Side effects

final counter = RM.inject<int>(
  () => 0,
  sideEffects: SideEffects.onData((value) => debugPrint('New value: $value')),
);

Pros and cons

  • Pros: little boilerplate; async states built in; DI and navigation helpers included.
  • Cons: much smaller community than Riverpod, Bloc or Provider; fewer learning resources; check recent releases before using it for a long-term project.

Try it yourself

Inject a bool darkMode state and use it in MaterialApp(themeMode: ...) inside an OnReactive, with a switch that toggles it.

Practise in the playground Updated