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.