Skip to content

Binding State to Dependency

A Reactter state( RtState ) such as Signal or any Hooks can be bound to the dependency, allowing the state to be manipulated directly from the dependency and to notify its listeners about any changes. Additionally, it ensures that the state is automatically disposed of when the dependency is no longer needed.

By integrating state directly within dependencies, you benefit from cleaner and more maintainable code. The automatic handling by Reactter means less boilerplate and fewer errors related to manual state management, leading to a more efficient development process. This approach simplifies the synchronization between state and its associated dependency, enhancing the overall responsiveness and reliability of your application.

Automatic binding

For that happened automatically, the state must be declared as a property or within constructor of the dependency. When this is done, Reactter automatically takes care of binding the state to the dependency, ensuring seamless state management and reactivity, e.g.:

count_controller.dart
1
import "package:reactter/reactter.dart";
2
3
class CountController {
4
// State declared as property
5
final uCount = UseState(0);
6
7
CountController() {
8
// State declared within constructor
9
UseEffect(() {
10
print("Count: ${uCount.value}");
11
}, [uCount]);
12
}
13
}

In the example above, the uCount state is declared as a property of the CountController class and the UseEffect hook is used within the constructor to react to changes in the uCount state, printing its value whenever it changes. This automatically binds the uCount state and UseEffect hook to the CountController instance, demonstrates how Reactter handles the binding and reactivity seamlessly.

Lazy binding

When a state is declared lazily, it is not automatically bound to the dependency. In such cases, you can use the Rt.lazyState method to bind the state to the dependency, e.g.:

count_controller.dart
1
import "package:reactter/reactter.dart";
2
3
class CountController {
4
final int initialCount;
5
6
late final uCount = Rt.lazyState(
7
() => UseState(this.initialCount),
8
this,
9
);
10
11
CountController([this.initialCount = 0]) {
12
UseEffect(() {
13
print("Count: ${uCount.value}");
14
}, [uCount]);
15
}
16
}

In the example above, the uCount state is declared lazily using the late keyword. To bind the state to the CountController instance, the Rt.lazyState method is used, passing the state creation function and the dependency instance as arguments. This ensures that when uCount is accessed, it will be automatically bound to the CountController instance.

Manual binding

While automatic binding simplifies state management, there may be scenarios where you need to manually bind the state to a dependency. Manual binding provides greater control over how and when the state is associated with the dependency.

To manually bind a state to a dependency, you need to explicitly link the state within the dependency using the bind method of the state, e.g.:

count_controller.dart
1
class CountController {
2
late final uCount = UseState(this.initialCount);
3
4
final int initialCount;
5
6
CountController([this.initialCount = 0]) {
7
count.bind(this);
8
}
9
}

In the example above, the uCount state is declared lazily using the late keyword. To manually bind the state to the CountController instance, the bind method is called within the constructor, passing the dependency instance as an argument. This ensures that the uCount state is associated with the CountController instance, e.g.:

Automatic unbinding

When a dependency is deleted, the associated state is automatically disposed of. This automatic unbinding mechanism simplifies state management and reduces the risk of memory leaks or resource wastage.

In the example below, the uCount state is automatically disposed of when the CountController instance is deleted, ensuring that resources are released efficiently:

main.dart
1
import "./count_controller.dart";
2
3
void main() {
4
final controller = Rt.create(() => CountController(10));
5
controller.uCount.value += 2; // Count: 12
6
Rt.delete<CountController>();
7
controller.uCount.value += 3; // Error: "Can't update when it's been disposed"
8
}

Manual unbinding

In some cases, you may need to manually unbind a state from a dependency. Manual unbinding provides greater control over when the state is released and can be useful in scenarios where you want to detach the state temporarily or permanently.

To manually unbind a state from a dependency, you can use the unbind method of the state, e.g.:

count_controller.dart
1
class CountController {
2
late final uCount = UseState(this.initialCount);
3
4
final int initialCount;
5
6
CountController([this.initialCount = 0]) {
7
count.bind(this);
8
}
9
10
void dispose() {
11
count.unbind(this);
12
}
13
}