A Flutter library for managing reactive state efficiently, supporting multiple independent instances with unique keys.
This library provides a flexible and efficient way to manage reactive state in Dart and Flutter applications. It supports multiple independent instances of state using unique keys, ensuring that each state instance is unique and does not interfere with others.
- Reactive State Management: Manage state reactively and efficiently.
- Multiple Independent Instances: Support for multiple instances of the same state type using unique keys.
- Singleton State: Ensure a single source of truth for each state instance.
- Reset State: Easily reset the state to its default value.
Add the following dependency to your pubspec.yaml
file:
dependencies:
reactive_notify: ^1.0.5
import 'package:reactive_notify/reactive_notify.dart';
ReactiveNotify<int> _state1 = ReactiveNotify<int>(() => 0);
ReactiveNotify<int> _state2 = ReactiveNotify<int>(() => 1);
void main() {
print(_state1.value); // Output: 0
print(_state2.value); // Output: 1
_state1.setState(5);
print(_state1.value); // Output: 5
print(_state2.value); // Output: 1
}
Use ReactiveBuilder
to build widgets that react to state changes.
import 'package:flutter/material.dart';
import 'package:reactive/reactive_notify.dart';
ReactiveNotify<int> state = ReactiveNotify<int>(() => 0);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Reactive State Example')),
body: Column(
children: [
ReactiveBuilder<int>(
valueListenable: state,
builder: (value) {
return Text('Value: $value');
},
),
ElevatedButton(
onPressed: () {
state.setState(state.value + 1);
},
child: Text('Increment'),
),
],
),
),
);
}
}
I recommend declaring your reactive states as global variables.
YOU DON'T NEED TO USE THEM IN THE BUILDER, if you want to use them only for one class,
use a hidden global variable, ReactiveNotify<int> _myLocalVariable = ReactiveNotify<int>(0)
You can reset the state to its default value.
state.resetState();
print(state.value); // Output: initial value
when(
()=> newValue,
onCompleteSetState(){
// Execute your function.
}
);
factory ReactiveNotify(T Function() initialValue)
Creates a new instance of ReactiveNotify
with a unique key and an initial value.
setState(T newValue)
: Sets a new value to the state and notifies listeners.resetState()
: Resets the state to its default value.when
( {required T Function() newState, required void Function() onCompleteState, void Function(Object error, StackTrace stackTrace)? onError}): We can execute function when completesetState
, on same context.
A widget that listens to a ValueListenable
and rebuilds itself when the value changes.
ReactiveBuilder({
required ValueListenable<T> valueListenable,
required Widget Function(T value) builder,
bool cleanStateOnDispose = false,
})
valueListenable
: The state to listen to.builder
: The builder function that takes the current context and state value.cleanStateOnDispose
: Whether to reset the state when the widget is disposed.
A very simple use case, interacting between different reactive states and generating a separate render in the same widget.
import 'package:flutter/material.dart';
import 'package:reactive/reactive_notify.dart';
enum ConnectionState {
connected,
unconnected,
connecting,
error,
uploading,
waiting,
signalOff,
errorOnSynchronized,
synchronizing,
synchronized,
waitingForSynchronization
}
/// Test for current state [ReactiveNotify].
final reactiveConnectionState = ReactiveNotify<ConnectionState>(() {
/// You can put any code for initial value.
return ConnectionState.signalOff;
});
/// Test for current state [ReactiveNotifyCallback].
final reactiveCallbackConnectionState = ReactiveNotifyCallback<ConnectionState>(
ConnectionState.waiting,
onStateChange: (value) {
/// You can put any validation or use another Reactive functions.
if (reactiveConnectionState.value == ConnectionState.unconnected) {
value = ConnectionState.error;
}
return value;
},
);
/// Test for current state [ReactiveNotifyInitializerCallback].
final reactiveStateInitializerCallback = ReactiveNotifyInitializerCallback<ConnectionState>(initializer: () {
if (reactiveConnectionState.value == ConnectionState.signalOff ||
reactiveCallbackConnectionState.value == ConnectionState.error) {
return ConnectionState.errorOnSynchronized;
}
return ConnectionState.waitingForSynchronization;
}, onStateChange: (state) {
if (reactiveConnectionState.value == ConnectionState.connected) {
state = ConnectionState.synchronizing;
}
if (reactiveCallbackConnectionState.value == ConnectionState.error) {
state = ConnectionState.errorOnSynchronized;
}
return state;
});
void main() {
/// Ensure flutter initialized.
WidgetsFlutterBinding.ensureInitialized();
runApp(
MaterialApp(
initialRoute: '/',
routes: {
'/': (BuildContext context) => const MyApp(),
},
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('ReactiveNotify'),
),
body: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/// 1. [ReactiveNotify] Current connection state
ReactiveBuilder(
valueListenable: reactiveConnectionState,
builder: (state) {
bool isConnected = state == ConnectionState.connected;
return Chip(
label: Text(
state.name,
),
avatar: Icon(
Icons.wifi,
color: isConnected ? Colors.green : Colors.red,
),
);
},
),
/// 2. Depend of connection for upload any file.
ReactiveBuilder(
valueListenable: reactiveCallbackConnectionState,
builder: (state) {
bool isConnected = state == ConnectionState.uploading;
return Chip(
label: Text(
state.name,
),
avatar: Icon(
Icons.cloud_download,
color: isConnected ? Colors.green : Colors.red,
),
);
},
),
/// 3. Depend of connection for upload any file.
ReactiveBuilder(
valueListenable: reactiveStateInitializerCallback,
builder: (state) {
bool isConnected = state != ConnectionState.errorOnSynchronized;
return Chip(
label: Text(
"${state?.name}",
),
avatar: Icon(
Icons.sync,
color: isConnected ? Colors.green : Colors.red,
),
);
},
),
],
),
),
floatingActionButton: OutlinedButton(
onPressed: () {
/// Variation unconnected and connected.
reactiveConnectionState.setState(reactiveConnectionState.value == ConnectionState.connected
? ConnectionState.unconnected
: ConnectionState.connected);
/// Try to connecting but the internal validation make error if reactiveConnectionState is unconnected.
reactiveCallbackConnectionState.setState(ConnectionState.uploading);
/// Try to synchronizing butt first make a internal validation
reactiveStateInitializerCallback.setState(ConnectionState.synchronizing);
},
child: const Text('ReactiveNotify'),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
It is possibly not the best test, but it generates a general idea.
This library is not intended to replace any state management solution. Instead, it aims to address certain challenges in managing reactive elements. It provides a simple, clean, lightweight, and quick solution for those situations where you need efficient state management without the need to learn the intricacies of a more robust library.
Contributions and comments are welcome 🤗.