Skip to main content

Random Stream

MobX provides a variety of reactive data structures to create your reactive-state. You must have already seen examples of the Observable, ObservableSet, ObservableMap, ObservableList, ObservableFuture. To add to this mix, we have the ObservableStream<T> that takes a stream and makes it reactive.

In this example, we will take a quick look at using the ObservableStream by observing a stream of random numbers.

info

See the complete code here.

The RandomStore

Let's start out by creating a Store to define our reactive state. The RandomStore defines a field named randomStream, that is pumped with random integers, every second. You can see the code below that defines the store:

part 'random_store.g.dart';

class RandomStore = _RandomStore with _$RandomStore;

abstract class _RandomStore with Store {
_RandomStore() {
_streamController = StreamController<int>();

_timer = Timer.periodic(const Duration(seconds: 1),
(_) => _streamController.add(_random.nextInt(100)));

randomStream = ObservableStream(_streamController.stream);
}

late final Timer _timer;

final _random = Random();

late final StreamController<int> _streamController;

late final ObservableStream<int?> randomStream;

// ignore: avoid_void_async
void dispose() async {
_timer.cancel();
await _streamController.close();
}
}

The ObservableStream<int> wraps a Stream<int> coming from the StreamController<int>. When the _timer ticks, we are putting a new random integer into the stream, now tracked by ObservableStream. If there is a reaction reading the randomStream.value somewhere, it will surely re-execute (react? :-)).

The reactive Observer

Well, in this case, our reaction happens to be the Observer which will simply show the new random number on the screen.

The code is fairly straightforward. We are just reading the randomStream.value and showing it inside the Text component.

class RandomNumberExample extends StatefulWidget {
const RandomNumberExample();

@override
_RandomNumberExampleState createState() => _RandomNumberExampleState();
}

class _RandomNumberExampleState extends State<RandomNumberExample> {
final RandomStore store = RandomStore();

@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: const Text('Random Number Generator'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Random number',
style: TextStyle(color: Colors.grey),
),
Observer(
builder: (_) {
final value = store.randomStream.value;

return Text(
'${value == null ? '---' : value}',
style: TextStyle(fontSize: 96),
);
},
),
],
),
));

@override
void dispose() {
store.dispose();
}
}

info

See the complete code here.