Skip to content

Instantly share code, notes, and snippets.

@terryl1900
Created July 26, 2022 03:54
Show Gist options
  • Save terryl1900/852dd0ab7a65b895d25275b2349f9d3f to your computer and use it in GitHub Desktop.
Save terryl1900/852dd0ab7a65b895d25275b2349f9d3f to your computer and use it in GitHub Desktop.
Counter app with a demo reactive state management solution.
import 'package:flutter/material.dart';
// A counter app with a basic reactive state management. It works similar to
// libraries like riverpod, mobx, getx.
// Obviously, this is a over simplified version, but hope it shows the gist.
// library.dart
/// A stack tracks Rx variables being recreated.
List<Rx> _creating = [];
/// Basic reactive variable.
class Rx<T> {
Rx(this.create) {
_creating.add(this);
_state = create();
_creating.removeLast();
}
late T _state;
final T Function() create; // User provided create function
final Set<Rx> listeners = {};
T call() {
listeners.add(_creating.last);
return _state;
}
/// Update state with [update] function or [create] function.
void update([T Function(T)? update]) {
_creating.add(this);
final oldState = _state;
_state = update != null ? update(_state) : create();
_creating.removeLast();
if (oldState != _state) {
for (var l in listeners) {
l.update();
}
}
}
}
class Consumer extends StatefulWidget {
const Consumer(this.builder, {Key? key}) : super(key: key);
final Widget Function(BuildContext context)? builder;
@override
State<Consumer> createState() => _ConsumerState();
}
class _ConsumerState extends State<Consumer> {
late Rx<Widget> builder = Rx<Widget>(() {
setState(() {});
return widget.builder!(context);
});
@override
Widget build(BuildContext context) {
builder.update();
return builder._state;
}
}
// counter.dart
final num1 = Rx(() => 1);
final num2 = Rx(() => 2);
final sum = Rx(() => num1() + num2());
// main.dart
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Counter example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Consumer((context) => Text('num1: ${num1()}')),
Consumer((context) => Text('num2: ${num2()}')),
Consumer((context) => Text('sum: ${sum()}')),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () => num1.update((n) => n + 1),
child: const Text('num1 +1')),
TextButton(
onPressed: () => num2.update((n) => n + 1),
child: const Text('num2 +1')),
],
),
],
),
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment