State management
State management is a critical aspect of any application, as it is responsible for controlling and maintaining data consistency over time. It facilitates updating and tracking changes in the state, ensuring a smooth user experience and stable application operation.
At Reactter, we understand the importance of state management, which is why we have designed a state management system that is efficient, reactive, and easy to use.
To continue, we will show you the mechanisms that Reactter offers for state management and how they work.
API
Reactter provides a variety of mechanisms for state management, including classes, hooks, and methods:
- Classes
- Hooks
- Methods
How it works
Reactter’s state management system is based on the concept of reactivity. Contrary to the prevailing notion that implementing reactive programming in Dart can be challenging, Reactter greatly simplifies this process. To dive into the concept, let’s start by exploring what constitutes a state in Reactter.
State
All states in Reactter are classes that inherit RtState
,
which encapsulates the data and behavior of a particular state, and provides a way to notify observers when the state changes.
State methods
RtState
class provides some methods for managing states. Let’s know about them:
-
update
: Executes a callback function and notify its observers that the state has changed. When it is invoked, it emits two lifecycle events to signal the state transition:Lifecycle.willUpdate
is emitted first, indicating the impending update.Lifecycle.didUpdate
is emitted once the update process is complete.
-
notify
: Forces the state to notify its observers. Unlikeupdate
, it emits only theLifecycle.didUpdate
event, as it doesn’t involve any preparatory steps before the notification. -
bind
: Establishes a connection between the state and a specific instance. This connection allows the instance to reactively update based on changes to the state. By binding the state, the instance becomes aware of changes to the state and can appropriately reflect those changes in its behavior. -
unbind
: Releases the connection between the state and the instance. When unbinding, the instance will no longer receive updates from the state. This can be useful when an instance is no longer actively using the state or when it needs to detach from the state temporarily or permanently. -
dispose
: Is responsible for cleaning up the state and any associated observers or resources. Disposing of the state ensures that it is properly released and no longer consumes memory or processing resources unnecessarily.
Example
Let’s see an countdown example using Signal
and understand what happens under the hood.
1import 'dart:async';2import 'package:reactter/reactter.dart';3
4// Create a reactive state called `count` using the `Signal` class5final count = Signal(10);6
7void main() async {8 // Liste n to the `didUpdate` event of the `count` state9 // and print the `value` of `count` each time it changes10 Rt.on(11 count,12 Lifecycle.didUpdate,13 (_, __) => print('Count: $count')14 );15
16 // Create a timer that invoked the `countdown` function every second17 await Timer.periodic(Duration(seconds: 1), countdown);18}19
20// Decrement the `value` of `count` by 1 each time the timer ticks21// and cancel the `timer` when the `value` of `count` reaches 022void countdown(Timer timer) {23 count.value -= 1;24
25 if (count.value == 0) {26 timer.cancel();27 }28}
Now let’s see what the Signal
class contains and how the count
state is updated in the example above.
1class Signal<T> with RtState {2 // State value3 T _value;4
5 T get value => _value;6
7 set value(T val) {8 if (_value == val) return;9
10 // Notify listeners that the state has changed,11 // triggering the `Lifecycle.willUpdate` and `Lifecycle.didUpdate` events in order.12 update((_) => _value = val);13 }14
15 // Private constructor, only a `Signal` instance can be created through the factory.16 Signal._(this._value);17
18 factory Signal(T value) {19 // Register a new state in the Reactter context20 return Rt.registerState(21 () => Signal._(value),22 );23 }24 [...]25}
During the process, as the value
of count
changes, the Lifecycle.didUpdate
event is triggered, which is fired by the update
method (signal.dart
, line 12).
This event is listened to by the Rt.on
method (main.dart
, line 10), which prints the value
of count
.
This occurs thanks to the reactivity of Reactter, which is responsible for notifying listeners by emitting events related to the lifecycle of the state.